/
ksync_object.h
323 lines (270 loc) · 10.9 KB
/
ksync_object.h
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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/*
* Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
*/
#ifndef ctrlplane_ksync_object_h
#define ctrlplane_ksync_object_h
#include <tbb/mutex.h>
#include <tbb/recursive_mutex.h>
#include <base/queue_task.h>
#include <base/timer.h>
#include <sandesh/sandesh_trace.h>
#include "ksync_entry.h"
#include "ksync_index.h"
/////////////////////////////////////////////////////////////////////////////
// Back-Ref management needs two trees,
// Back-Ref tree:
// --------------
// An entry of type <key-entry, back-ref-entry> means that key-entry is
// waiting for back-ref-entry to be added to kernel.
// Note, there can be more than one key-entry waiting on a single
// back-ref-entry. However, a key-entry can be waiting on only one
// back-ref-entry at a time.
//
// This is a dynamic tree. Entries are added only when constraints are not
// met. Entries will not be in tree when constraints are met.
//
// Fwd-Ref tree:
// -------------
// Holds forward reference information. If Object-A is waiting on Object-B
// Fwd-Ref tree will have an entry with Object-A as key and Object-B as data.
/////////////////////////////////////////////////////////////////////////////
struct KSyncFwdReference {
KSyncFwdReference(KSyncEntry *key, KSyncEntry *ref) : key_(key),
reference_(ref) { };
bool operator<(const KSyncFwdReference &rhs) const {
return (key_ < rhs.key_);
};
boost::intrusive::set_member_hook<> node_;
KSyncEntry *key_;
KSyncEntry *reference_;
};
struct KSyncBackReference {
KSyncBackReference(KSyncEntry *key, KSyncEntry *ref) :
key_(key), back_reference_(ref) { };
bool operator<(const KSyncBackReference &rhs) const {
if (key_ < rhs.key_)
return true;
if (key_ > rhs.key_)
return false;
if (back_reference_ < rhs.back_reference_)
return true;
return false;
};
boost::intrusive::set_member_hook<> node_;
KSyncEntry *key_;
KSyncEntry *back_reference_;
};
class KSyncObject {
public:
typedef boost::intrusive::member_hook<KSyncEntry,
boost::intrusive::set_member_hook<>,
&KSyncEntry::node_> KSyncObjectNode;
typedef boost::intrusive::set<KSyncEntry, KSyncObjectNode> Tree;
typedef boost::intrusive::member_hook<KSyncFwdReference,
boost::intrusive::set_member_hook<>,
&KSyncFwdReference::node_> KSyncFwdRefNode;
typedef boost::intrusive::set<KSyncFwdReference, KSyncFwdRefNode> FwdRefTree;
typedef boost::intrusive::member_hook<KSyncBackReference,
boost::intrusive::set_member_hook<>,
&KSyncBackReference::node_> KSyncBackRefNode;
typedef boost::intrusive::set<KSyncBackReference, KSyncBackRefNode> BackRefTree;
// Default constructor. No index needed
KSyncObject(const std::string &name);
// Constructor for objects needing index
KSyncObject(const std::string &name, int max_index);
// Destructor
virtual ~KSyncObject();
// Initialise stale entry cleanup state machine.
void InitStaleEntryCleanup(boost::asio::io_service &ios,
uint32_t cleanup_time, uint32_t cleanup_intvl,
uint16_t entries_per_intvl);
// Notify an event to KSyncEvent state-machine
void NotifyEvent(KSyncEntry *entry, KSyncEntry::KSyncEvent event);
// Call Notify event with mutex lock held
void SafeNotifyEvent(KSyncEntry *entry, KSyncEntry::KSyncEvent event);
// Handle Netlink ACK message
virtual void NetlinkAck(KSyncEntry *entry, KSyncEntry::KSyncEvent event);
// Add a back-reference entry
void BackRefAdd(KSyncEntry *key, KSyncEntry *reference);
// Delete a back-reference entry
void BackRefDel(KSyncEntry *key);
// Re-valuate the back-reference entries
void BackRefReEval(KSyncEntry *key);
// Create an entry
KSyncEntry *Create(const KSyncEntry *key);
KSyncEntry *Create(const KSyncEntry *key, bool skip_lookup);
// Create a Stale entry, which needs to be cleanedup as part for
// stale entry cleanup (timer).
// Derived class can choose to create this entry to manage stale
// states in Kernel
KSyncEntry *CreateStale(const KSyncEntry *key);
// Called on change to ksync_entry. Will resulting in sync of the entry
void Change(KSyncEntry *entry);
// Delete a KSyncEntry
void Delete(KSyncEntry *entry);
// Query function. Key is in entry
KSyncEntry *Find(const KSyncEntry *key);
// Get Next Function.
KSyncEntry *Next(const KSyncEntry *entry) const;
// Query KSyncEntry for key in entry. Create temporary entry if not present
KSyncEntry *GetReference(const KSyncEntry *key);
// Called from Create or GetReference to Allocate a KSyncEntry.
// The KSyncEntry must be populated with fields in key and index
virtual KSyncEntry *Alloc(const KSyncEntry *key, uint32_t index) = 0;
virtual void Free(KSyncEntry *entry);
//Callback when all the entries in table are deleted
virtual void EmptyTable(void) { };
bool IsEmpty(void) { return tree_.empty(); };
virtual bool DoEventTrace(void) { return true; }
virtual void PreFree(KSyncEntry *entry) { }
static void Shutdown();
std::size_t Size() { return tree_.size(); }
void set_delete_scheduled() { delete_scheduled_ = true;}
bool delete_scheduled() { return delete_scheduled_;}
virtual SandeshTraceBufferPtr GetKSyncTraceBuf() {return KSyncTraceBuf;}
protected:
// Create an entry with default state. Used internally
KSyncEntry *CreateImpl(const KSyncEntry *key);
// Clear Stale Entry flag
void ClearStale(KSyncEntry *entry);
// Big lock on the tree
// TODO: Make this more fine granular
mutable tbb::recursive_mutex lock_;
void ChangeKey(KSyncEntry *entry, uint32_t arg);
virtual void UpdateKey(KSyncEntry *entry, uint32_t arg) { }
// derived class needs to implement GetKey,
// default impl will assert
virtual uint32_t GetKey(KSyncEntry *entry);
private:
friend class KSyncEntry;
friend void TestTriggerStaleEntryCleanupCb(KSyncObject *obj);
// Free indication of an KSyncElement.
// Removes from tree and free index if allocated earlier
void FreeInd(KSyncEntry *entry, uint32_t index);
void NetlinkAckInternal(KSyncEntry *entry, KSyncEntry::KSyncEvent event);
bool IsIndexValid() const { return need_index_; }
// timer Callback to trigger delete of stale entries.
bool StaleEntryCleanupCb();
//Callback to do cleanup when DEL ACK is received.
virtual void CleanupOnDel(KSyncEntry *kentry) {}
// Tree of all KSyncEntries
Tree tree_;
// Forward reference tree
static FwdRefTree fwd_ref_tree_;
// Back reference tree
static BackRefTree back_ref_tree_;
// Does the KSyncEntry need index?
bool need_index_;
// Index table for KSyncObject
KSyncIndexTable index_table_;
// scheduled for deletion
bool delete_scheduled_;
// stale entry tree
std::set<KSyncEntry::KSyncEntryPtr> stale_entry_tree_;
// Stale Entry Cleanup Timer
Timer *stale_entry_cleanup_timer_;
uint32_t stale_entry_cleanup_intvl_;
uint16_t stale_entries_per_intvl_;
SandeshTraceBufferPtr KSyncTraceBuf;
DISALLOW_COPY_AND_ASSIGN(KSyncObject);
};
// Special KSyncObject for DB client
class KSyncDBObject : public KSyncObject {
public:
// Response to DB Filter API using which derived class can choose to
// ignore or trigger delete for some of the DB entries.
// This can be used where we don't want to handle certain type of OPER
// DB entries in KSync, using this simplifies the behaviour defination
// for KSync Object.
enum DBFilterResp {
DBFilterAccept, // Accept DB Entry Add/Change for processing
DBFilterIgnore, // Ignore DB Entry Add/Change
DBFilterDelete, // Ignore DB Entry Add/Change and clear previous state
DBFilterDelAdd, // Delete current ksync and add new one (key change)
DBFilterMax
};
// Create KSyncObject. DB Table will be registered later
KSyncDBObject(const std::string &name);
KSyncDBObject(const std::string &name, int max_index);
KSyncDBObject(const std::string &name, DBTableBase *table);
// KSync DB Object with index allocation
KSyncDBObject(const std::string &name,
DBTableBase *table,
int max_index);
// Destructor
virtual ~KSyncDBObject();
// Register to a DB Table
void RegisterDb(DBTableBase *table);
//Unregister from a DB table
void UnregisterDb(DBTableBase *table);
// Callback registered to DB Table
void Notify(DBTablePartBase *partition, DBEntryBase *entry);
DBTableBase *GetDBTable() { return table_; }
DBTableBase::ListenerId GetListenerId(DBTableBase *table);
// Function to filter DB Entries to be used, default behaviour will accept
// All DB Entries, needs to be overriden by derived class to get desired
// behavior.
virtual DBFilterResp DBEntryFilter(const DBEntry *entry,
const KSyncDBEntry *ksync);
// Populate Key in KSyncEntry from DB Entry.
// Used for lookup of KSyncEntry from DBEntry
virtual KSyncEntry *DBToKSyncEntry(const DBEntry *entry) = 0;
void set_test_id(DBTableBase::ListenerId id);
private:
//Callback to do cleanup when DEL ACK is received.
virtual void CleanupOnDel(KSyncEntry *kentry);
DBTableBase *table_;
DBTableBase::ListenerId id_;
DBTableBase::ListenerId test_id_;
KSyncIndexTable index_table_;
DISALLOW_COPY_AND_ASSIGN(KSyncDBObject);
};
struct KSyncObjectEvent {
enum Event {
UNKNOWN,
UNREGISTER,
DELETE,
};
KSyncObjectEvent(KSyncObject *obj, Event event) :
obj_(obj), event_(event) {
}
KSyncEntry::KSyncEntryPtr ref_;
KSyncObject *obj_;
Event event_;
};
class KSyncObjectManager {
public:
static const int kMaxEntriesProcess = 100;
KSyncObjectManager();
~KSyncObjectManager();
bool Process(KSyncObjectEvent *event);
void Enqueue(KSyncObjectEvent *event);
static KSyncEntry *default_defer_entry();
static KSyncObjectManager *Init();
static void Shutdown();
static void Unregister(KSyncObject *);
void Delete(KSyncObject *);
static KSyncObjectManager *GetInstance();
private:
WorkQueue<KSyncObjectEvent *> *event_queue_;
static std::auto_ptr<KSyncEntry> default_defer_entry_;
static KSyncObjectManager *singleton_;
};
class KSyncDebug {
public:
static void set_debug(bool debug) { debug_ = debug;}
static bool debug() { return debug_; }
private:
static bool debug_;
};
#define KSYNC_TRACE(obj, parent, ...)\
do {\
KSync##obj::TraceMsg(parent->GetKSyncTraceBuf(), __FILE__, __LINE__, ##__VA_ARGS__);\
} while (false);\
#define KSYNC_ASSERT(cond)\
do {\
if (KSyncDebug::debug() == true) {\
assert(cond);\
}\
} while (false);\
#endif // ctrlplane_ksync_object_h