-
Notifications
You must be signed in to change notification settings - Fork 10
/
pit-cs.go
237 lines (197 loc) · 6.55 KB
/
pit-cs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/* YaNFD - Yet another NDN Forwarding Daemon
*
* Copyright (C) 2020-2021 Eric Newberry.
*
* This file is licensed under the terms of the MIT License, as found in LICENSE.md.
*/
package table
import (
"time"
"github.com/named-data/YaNFD/ndn"
enc "github.com/zjkmxy/go-ndn/pkg/encoding"
)
// PitCsTable dictates what functionality a Pit-Cs table should implement
// Warning: All functions must be called in the same forwarding goroutine as the creation of the table.
type PitCsTable interface {
InsertInterest(pendingPacket *ndn.PendingPacket, hint enc.Name, inFace uint64) (PitEntry, bool)
RemoveInterest(pitEntry PitEntry) bool
FindInterestExactMatchEnc(pendingPacket *ndn.PendingPacket) PitEntry
FindInterestPrefixMatchByDataEnc(pendingPacket *ndn.PendingPacket, token *uint32) []PitEntry
PitSize() int
InsertData(pendingPacket *ndn.PendingPacket)
FindMatchingDataFromCS(pendingPacket *ndn.PendingPacket) CsEntry
CsSize() int
IsCsAdmitting() bool
IsCsServing() bool
eraseCsDataFromReplacementStrategy(index uint64)
updatePitExpiry(pitEntry PitEntry)
// UpdateTimer returns the channel used to signal regular Update() calls in the forwarding thread.
// <- UpdateTimer() and Update() must be called in pairs.
UpdateTimer() <-chan struct{}
// Update() does whatever the PIT table needs to do regularly.
// It may schedule the next UpdateTimer().
Update()
}
// basePitCsTable contains properties common to all PIT-CS tables
type basePitCsTable struct{}
// PitEntry dictates what entries in a PIT-CS table should implement
type PitEntry interface {
PitCs() PitCsTable
EncName() enc.Name
CanBePrefix() bool
MustBeFresh() bool
ForwardingHintNew() enc.Name
// Interests must match in terms of Forwarding Hint to be aggregated in PIT.
InRecords() map[uint64]*PitInRecord // Key is face ID
OutRecords() map[uint64]*PitOutRecord // Key is face ID
ExpirationTime() time.Time
SetExpirationTime(t time.Time)
Satisfied() bool
SetSatisfied(isSatisfied bool)
Token() uint32
InsertInRecord(pendingPacket *ndn.PendingPacket, face uint64, incomingPitToken []byte) (*PitInRecord, bool)
InsertOutRecord(pendingPacket *ndn.PendingPacket, face uint64) *PitOutRecord
GetOutRecords() []*PitOutRecord
ClearOutRecords()
ClearInRecords()
}
// basePitEntry contains PIT entry properties common to all tables.
type basePitEntry struct {
// lowercase fields so that they aren't exported
encname enc.Name
canBePrefix bool
mustBeFresh bool
forwardingHintNew enc.Name
// Interests must match in terms of Forwarding Hint to be
// aggregated in PIT.
inRecords map[uint64]*PitInRecord // Key is face ID
outRecords map[uint64]*PitOutRecord // Key is face ID
expirationTime time.Time
satisfied bool
token uint32
}
// PitInRecord records an incoming Interest on a given face.
type PitInRecord struct {
Face uint64
LatestTimestamp time.Time
LatestEncInterest *ndn.PendingPacket
LatestEncNonce uint32
ExpirationTime time.Time
PitToken []byte
}
// PitOutRecord records an outgoing Interest on a given face.
type PitOutRecord struct {
Face uint64
LatestTimestamp time.Time
LatestEncInterest *ndn.PendingPacket
LatestEncNonce uint32
ExpirationTime time.Time
}
// CsEntry is an entry in a thread's CS.
type CsEntry interface {
Index() uint64 // the hash of the entry, for fast lookup
StaleTime() time.Time
EncData() *ndn.PendingPacket
}
type baseCsEntry struct {
index uint64
staleTime time.Time
encData *ndn.PendingPacket
}
// InsertInRecord finds or inserts an InRecord for the face, updating the
// metadata and returning whether there was already an in-record in the entry.
func (bpe *basePitEntry) InsertInRecord(
pendingPacket *ndn.PendingPacket, face uint64, incomingPitToken []byte,
) (*PitInRecord, bool) {
var record *PitInRecord
var ok bool
if record, ok = bpe.inRecords[face]; !ok {
record := new(PitInRecord)
record.Face = face
record.LatestEncNonce = *pendingPacket.EncPacket.Interest.NonceV
record.LatestTimestamp = time.Now()
record.LatestEncInterest = pendingPacket
record.ExpirationTime = time.Now().Add(time.Millisecond * 4000)
record.PitToken = incomingPitToken
bpe.inRecords[face] = record
return record, false
}
// Existing record
record.LatestEncNonce = *pendingPacket.EncPacket.Interest.NonceV
record.LatestTimestamp = time.Now()
record.LatestEncInterest = pendingPacket
record.ExpirationTime = time.Now().Add(time.Millisecond * 4000)
return record, true
}
// SetExpirationTimerToNow updates the expiration timer to the current time.
func SetExpirationTimerToNow(e PitEntry) {
e.SetExpirationTime(time.Now())
e.PitCs().updatePitExpiry(e)
}
// UpdateExpirationTimer updates the expiration timer to the latest expiration
// time of any in or out record in the entry.
func UpdateExpirationTimer(e PitEntry) {
e.SetExpirationTime(time.Now())
for _, record := range e.InRecords() {
if record.ExpirationTime.After(e.ExpirationTime()) {
e.SetExpirationTime(record.ExpirationTime)
}
}
for _, record := range e.OutRecords() {
if record.ExpirationTime.After(e.ExpirationTime()) {
e.SetExpirationTime(record.ExpirationTime)
}
}
e.PitCs().updatePitExpiry(e)
}
// /// Setters and Getters /////
func (bpe *basePitEntry) EncName() enc.Name {
return bpe.encname
}
func (bpe *basePitEntry) CanBePrefix() bool {
return bpe.canBePrefix
}
func (bpe *basePitEntry) MustBeFresh() bool {
return bpe.mustBeFresh
}
func (bpe *basePitEntry) ForwardingHintNew() enc.Name {
return bpe.forwardingHintNew
}
func (bpe *basePitEntry) InRecords() map[uint64]*PitInRecord {
return bpe.inRecords
}
func (bpe *basePitEntry) OutRecords() map[uint64]*PitOutRecord {
return bpe.outRecords
}
// ClearInRecords removes all in-records from the PIT entry.
func (bpe *basePitEntry) ClearInRecords() {
bpe.inRecords = make(map[uint64]*PitInRecord)
}
// ClearOutRecords removes all out-records from the PIT entry.
func (bpe *basePitEntry) ClearOutRecords() {
bpe.outRecords = make(map[uint64]*PitOutRecord)
}
func (bpe *basePitEntry) ExpirationTime() time.Time {
return bpe.expirationTime
}
func (bpe *basePitEntry) SetExpirationTime(t time.Time) {
bpe.expirationTime = t
}
func (bpe *basePitEntry) Satisfied() bool {
return bpe.satisfied
}
func (bpe *basePitEntry) SetSatisfied(isSatisfied bool) {
bpe.satisfied = isSatisfied
}
func (bpe *basePitEntry) Token() uint32 {
return bpe.token
}
func (bce *baseCsEntry) Index() uint64 {
return bce.index
}
func (bce *baseCsEntry) StaleTime() time.Time {
return bce.staleTime
}
func (bce *baseCsEntry) EncData() *ndn.PendingPacket {
return bce.encData
}