OpenSDN source code
sandesh_uve.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 //
6 // sandesh_uve.h
7 //
8 // This file has the interface for the generator-side UVE
9 // cache.
10 //
11 
12 #ifndef __SANDESH_UVE_H__
13 #define __SANDESH_UVE_H__
14 
15 #include <map>
16 #include <vector>
17 #include <mutex>
18 
19 #include <boost/ptr_container/ptr_map.hpp>
20 #include <boost/assign/ptr_map_inserter.hpp>
21 #include <sandesh/sandesh_types.h>
22 #include <sandesh/sandesh.h>
23 #include <tbb/concurrent_hash_map.h>
24 #include <boost/functional/hash.hpp>
25 
27 
28 // This class holds a map of all per-SandeshUVE-type caches.
29 // Each cache registers with this class during static initialization.
30 //
31 // The Sandesh Session state machine uses this class to
32 // find the per-SandeshUVE-type caches and invoke operations on them.
33 //
35 public:
36  typedef std::pair<int, SandeshUVEPerTypeMap *> uve_global_elem;
37  typedef std::map<std::string, uve_global_elem> uve_global_map;
38  typedef std::map<std::string, std::string> ds_conf_elem;
39 
40  static void RegisterType(const std::string &s, SandeshUVEPerTypeMap *tmap,
41  int period) {
42  assert(GetMap()->insert(std::make_pair(s,
43  std::make_pair(period, tmap))).second);
44  }
45  static const uve_global_elem TypeMap(const std::string &s) {
46  uve_global_map::const_iterator it = GetMap()->find(s);
47  if (it == GetMap()->end())
48  return std::make_pair(0, (SandeshUVEPerTypeMap *)(NULL));
49  else
50  return it->second;
51  }
52  static void SyncAllMaps(const std::map<std::string,uint32_t> &,
53  bool periodic = false);
54  static uint32_t Clear(const std::string& proxy, int partition);
55  static bool InitDerivedStats(
56  const std::map<std::string, ds_conf_elem> &);
57  static void SyncIntrospect(std::string tname, std::string table, std::string key);
58 
59  static uve_global_map::const_iterator Begin() { return GetMap()->begin(); }
60  static uve_global_map::const_iterator End() { return GetMap()->end(); }
61  static const int kProxyPartitions = 30;
62 private:
64 
65  static uve_global_map * GetMap() {
66  if (!map_) {
67  map_ = new uve_global_map();
68  }
69  return map_;
70  }
71 };
72 
73 
74 // This is the interface of the per-SandeshUVE-type caches.
75 //
77 public:
78  virtual ~SandeshUVEPerTypeMap() { }
79  virtual uint32_t TypeSeq() const = 0;
80  virtual uint32_t SyncUVE(const std::string &table, SandeshUVE::SendType st,
81  uint32_t seqno, uint32_t cycle, const std::string &ctx) = 0;
82  virtual bool InitDerivedStats(
83  const std::map<std::string,std::string> & dsconf) = 0;
84  virtual bool SendUVE(const std::string& table, const std::string& name,
85  const std::string& ctx) const = 0;
86  virtual std::map<std::string, std::string> GetDSConf(void) const = 0;
87  virtual int GetTimeout(void) const = 0;
88  virtual uint32_t ClearUVEs(const std::string& proxy, int partition) = 0;
89 };
90 
91 
92 // This is the per-SandeshUVE-type cache.
93 //
94 //
95 // It is parameterized on the Sandesh type, and the underlying UVE Type.
96 //
97 // Assumptions about Sandesh Type:
98 // - Has a single element called "data", of the UVE type.
99 // - Provides static "Send" function.
100 // - Per-object sequence number is available as "lseqnum()"
101 //
102 // Assumptions about UVE Type
103 // - Can be constructed with 0 arguments (default constructor)
104 // - Has a boolean field called "deleted"
105 // - The UVE key is in a field called "name"
106 //
107 
108 
109 template<typename T, typename U, int P, int TM>
111 public:
112 
113  struct HashCompare {
114  static size_t hash( const std::string& key )
115  { return boost::hash_value(key); }
116  static bool equal( const std::string& key1, const std::string& key2 )
117  { return ( key1 == key2 ); }
118  };
119 
120  struct UVEMapEntry {
121  UVEMapEntry(const std::string &table, uint32_t seqnum,
123  data(table), seqno(seqnum), level(level) {
124  }
125  U data;
126  uint32_t seqno;
128  };
129 
130  // The key is the table name
131  typedef boost::ptr_map<std::string, UVEMapEntry> uve_table_map;
132 
133  // The key is the UVE-Key
134  typedef tbb::concurrent_hash_map<std::string, uve_table_map, HashCompare > uve_cmap;
135 
137  dsconf_(T::_DSConf()) {}
138 
139  // This function is called whenever a SandeshUVE is sent from
140  // the generator to the collector.
141  // It updates the cache.
142  bool UpdateUVE(U& data, uint32_t seqnum, uint64_t mono_usec,
143  SandeshLevel::type level) {
144  bool send = false;
145  const std::string &table = data.table_;
146  assert(!table.empty());
147  const std::string &s = data.get_name();
148  if (!mono_usec) mono_usec = ClockMonotonicUsec();
149 
150  // pickup DS Config
151  std::unique_lock<std::mutex> lock(uve_mutex_);
152  std::map<string,string> dsconf = dsconf_;
153 
154  // If we are going to erase, we need a global lock
155  // to coordinate with iterators
156  // To prevent deadlock, we always acquire global lock
157  // before accessor
158  if (!data.get_deleted()) {
159  lock.unlock();
160  }
161  typename uve_cmap::accessor a;
162 
163  // Ensure that the entry exists, and we have an accessor to it
164  while (true) {
165  if (cmap_.find(a, s)) break;
166  else {
167  if (cmap_.insert(a, s)) break;
168  }
169  }
170 
171  typename uve_table_map::iterator imapentry = a->second.find(table);
172  if (imapentry == a->second.end()) {
173  std::auto_ptr<UVEMapEntry> ume(new
174  UVEMapEntry(data.table_, seqnum, level));
175  T::_InitDerivedStats(ume->data, dsconf);
176  send = T::UpdateUVE(data, ume->data, mono_usec, level);
177  imapentry = a->second.insert(table, ume).first;
178  } else {
179  if (TM != 0) {
180  // If we get an update , mark this UVE so that it is not
181  // deleted during the next round of periodic processing
182  imapentry->second->data.set_deleted(false);
183  }
184  send = T::UpdateUVE(data, imapentry->second->data, mono_usec,
185  level);
186  imapentry->second->seqno = seqnum;
187  }
188  if (data.get_deleted()) {
189  a->second.erase(imapentry);
190  if (a->second.empty()) cmap_.erase(a);
191  lock.unlock();
192  }
193 
194  return send;
195  }
196 
197  // Clear all UVEs in this cache
198  // This is used ONLY with proxy groups
199  uint32_t ClearUVEs(void) {
200 
201  // Global lock is needed for iterator
202  std::scoped_lock lock(uve_mutex_);
203  uint32_t count = 0;
204  (const_cast<SandeshUVEPerTypeMapImpl<T,U,P,TM> *>(this))->cmap_.rehash();
205  typename uve_cmap::iterator git = cmap_.begin();
206  while (git != cmap_.end()) {
207  typename uve_cmap::accessor a;
208  if (!cmap_.find(a, git->first)) continue;
209  typename uve_table_map::iterator uit = a->second.begin();
210  while (uit != a->second.end()) {
211  SANDESH_LOG(INFO, __func__ << " Clearing " << uit->first <<
212  " val " << uit->second->data.log() << " proxy " <<
213  SandeshStructProxyTrait<U>::get(uit->second->data) <<
214  " seq " << uit->second->seqno);
215  uit->second->data.set_deleted(true);
216  T::Send(uit->second->data, uit->second->level,
217  SandeshUVE::ST_SYNC, uit->second->seqno, 0, "");
218  count++;
219  ++uit;
220  }
221  ++git;
222  }
223  cmap_.clear();
224  return count;
225  }
226 
227  bool InitDerivedStats(const std::map<std::string,std::string> & dsconf) {
228 
229  // Global lock is needed for iterator
230  std::scoped_lock lock(uve_mutex_);
231 
232  // Copy the existing configuration
233  // We will be replacing elements in it.
234  std::map<std::string,std::string> dsnew = dsconf_;
235 
236  bool failure = false;
237  for (map<std::string,std::string>::const_iterator n_iter = dsconf.begin();
238  n_iter != dsconf.end(); n_iter++) {
239  if (dsnew.find(n_iter->first) != dsnew.end()) {
240  SANDESH_LOG(INFO, __func__ << " Overide DSConf for " <<
241  n_iter->first << " , " << dsnew[n_iter->first] <<
242  " with " << n_iter->second);
243  dsnew[n_iter->first] = n_iter->second;
244  } else {
245  SANDESH_LOG(INFO, __func__ << " Cannot find DSConf for " <<
246  n_iter->first << " , " << n_iter->second);
247  failure = true;
248  }
249  }
250 
251  if (failure) return false;
252 
253  // Copy the new conf into the old one if there we no errors
254  dsconf_ = dsnew;
255 
256  (const_cast<SandeshUVEPerTypeMapImpl<T,U,P,TM> *>(this))->cmap_.rehash();
257  for (typename uve_cmap::iterator git = cmap_.begin();
258  git != cmap_.end(); git++) {
259  typename uve_cmap::accessor a;
260  if (!cmap_.find(a, git->first)) continue;
261  for (typename uve_table_map::iterator uit = a->second.begin();
262  uit != a->second.end(); uit++) {
263  SANDESH_LOG(INFO, __func__ << " Reset Derived Stats for " <<
264  git->first);
265  T::_InitDerivedStats(uit->second->data, dsconf_);
266  }
267  }
268  return true;
269  }
270 
271  uint32_t SyncUVE(const std::string &table,
273  uint32_t seqno, uint32_t cycle,
274  const std::string &ctx) {
275  // Global lock is needed for iterator
276  std::scoped_lock lock(uve_mutex_);
277  uint32_t count = 0;
278  (const_cast<SandeshUVEPerTypeMapImpl<T,U,P,TM> *>(this))->cmap_.rehash();
279  typename uve_cmap::iterator git = cmap_.begin();
280  while (git != cmap_.end()) {
281  typename uve_cmap::accessor a;
282  if (!cmap_.find(a, git->first)) continue;
283  typename uve_table_map::iterator uit = a->second.begin();
284  while (uit != a->second.end()) {
285  typename uve_table_map::iterator dit = a->second.end();
286  if (!table.empty() && uit->first != table) continue;
287  if ((seqno < uit->second->seqno) || (seqno == 0)) {
288  if (ctx.empty()) {
289  SANDESH_LOG(INFO, __func__ << " Syncing " << uit->first <<
290  " val " << uit->second->data.log() << " proxy " <<
291  SandeshStructProxyTrait<U>::get(uit->second->data) <<
292  " seq " << uit->second->seqno);
293  }
294  T::Send(uit->second->data, uit->second->level, st,
295  uit->second->seqno, cycle, ctx);
296  if ((TM != 0) && (st == SandeshUVE::ST_PERIODIC)) {
297  if ((cycle % TM) == 0) {
298  if (uit->second->data.get_deleted()) {
299  // This UVE was marked for deletion during the
300  // last periodic processing round, and there
301  // have been no UVE updates
302  dit = uit;
303  } else {
304  // Mark this UVE to be deleted during the next
305  // periodic processing round, unless it is updated
306  uit->second->data.set_deleted(true);
307  }
308  }
309  }
310  count++;
311  }
312  ++uit;
313  if (dit != a->second.end()) a->second.erase(dit);
314  }
315  ++git;
316  if (a->second.empty()) cmap_.erase(a);
317  }
318  return count;
319  }
320 
321  bool SendUVE(const std::string& table, const std::string& name,
322  const std::string& ctx) const {
323  bool sent = false;
324  typename uve_cmap::const_accessor a;
325  if (cmap_.find(a, name)) {
326  for (typename uve_table_map::const_iterator uve_entry = a->second.begin();
327  uve_entry != a->second.end(); uve_entry++) {
328  if (!table.empty() && uve_entry->first != table) continue;
329  sent = true;
330  T::Send(uve_entry->second->data, uve_entry->second->level,
332  uve_entry->second->seqno, 0, ctx);
333  }
334  }
335  return sent;
336  }
337 
338  std::map<std::string, std::string> GetDSConf(void) const {
339  return dsconf_;
340  }
341 
342 private:
343 
345  std::map<std::string, std::string> dsconf_;
346  mutable std::mutex uve_mutex_;
347 };
348 
349 #define SANDESH_UVE_DEF(x,y,z,w) \
350  static SandeshUVEPerTypeMapGroup<x, y, z, w> uvemap ## x(#y)
351 
352 template<typename T, typename U, int P, int TM>
354 public:
356 
357  // Native map
358  typedef boost::ptr_map<string, uve_emap> uve_nmap;
359 
360  // One UVE Type Map per partition
361  typedef boost::ptr_map<int, uve_emap> uve_pmap;
362 
363  // One set of per-partition UVE Type Maps for each proxy group
364  typedef boost::ptr_map<string, uve_pmap> uve_gmap;
365 
366  SandeshUVEPerTypeMapGroup(char const * u_name) {
367  std::string native_name(std::string(""));
368  uve_emap* ne = new uve_emap;
369  native_group_map_.insert(native_name, ne);
370  nativep_ = ne;
371  SandeshUVETypeMaps::RegisterType(u_name, this, P);
372  }
373 
374  string GetNMapUVEname(U &data) {
375  std::string proxy = SandeshStructProxyTrait<U>::get(data);
376  return proxy;
377  }
378 
379  // Get the native map for the given UVE proxy name
380  uve_emap *GetNMap(const std::string& name) {
381  if (name == std::string("")){
382  return(nativep_);
383  }
384  std::scoped_lock lock(nmutex_);
385  if (native_group_map_.find(name) == native_group_map_.end()) {
386  uve_emap* ne = new uve_emap;
387  std::string native_name(name);
388  native_group_map_.insert(native_name, ne);
389  }
390  return &(native_group_map_.at(name));
391  }
392 
393  // Get the Native UVE and Native proxy UVE maps for this Native type
394  std::vector<uve_emap*> GetNMaps(void) {
395  std::scoped_lock lock(nmutex_);
396  std::vector<uve_emap *> nev;
397  for (typename uve_nmap::iterator uni = native_group_map_.begin();
398  uni != native_group_map_.end(); uni++) {
399  nev.push_back(uni->second);
400  }
401  return nev;
402  }
403 
404  // Get the partition UVE Type maps for the given proxy group
405  uve_pmap *GetGMap(const std::string& proxy) {
406  std::scoped_lock lock(gmutex_);
407  if (group_map_.find(proxy) == group_map_.end()) {
408  uve_pmap* up = new uve_pmap;
409  std::string kstring(proxy);
410  for (size_t idx=0; idx<SandeshUVETypeMaps::kProxyPartitions; idx++) {
411  boost::assign::ptr_map_insert(*up)(idx);
412  }
413  group_map_.insert(kstring ,up);
414  }
415  return &(group_map_.at(proxy));
416  }
417 
418  // Get the partition UVE Type maps for all proxy groups
419  std::vector<uve_pmap *> GetGMaps(void) {
420  std::scoped_lock lock(gmutex_);
421  std::vector<uve_pmap *> pv;
422  for (typename uve_gmap::iterator ugi = group_map_.begin();
423  ugi != group_map_.end(); ugi++) {
424  pv.push_back(ugi->second);
425  }
426  return pv;
427  }
428 
429  // This function can be used by the Sandesh Session state machine
430  // to get the seq num of the last message sent for this SandeshUVE type
431  uint32_t TypeSeq(void) const {
432  return T::lseqnum();
433  }
434 
435  int GetTimeout(void) const {
436  return TM;
437  }
438 
439  // Sync UVEs for both the native UVE Map and the proxy groups
440  uint32_t SyncUVE(const std::string &table,
442  uint32_t seqno, uint32_t cycle,
443  const std::string &ctx) {
444  uint32_t count=0;
445  std::vector<uve_emap *> nev = GetNMaps();
446  for (size_t idx=0; idx<nev.size(); idx++) {
447  count += nev[idx]->SyncUVE(table, st, seqno, cycle,ctx);
448  }
449 
450  std::vector<uve_pmap *> pv = GetGMaps();
451  for (size_t jdx=0; jdx<pv.size(); jdx++) {
452  for (size_t idx=0; idx<SandeshUVETypeMaps::kProxyPartitions; idx++) {
453  count += pv[jdx]->at(idx).SyncUVE(table, st, seqno, cycle, ctx);
454  }
455  }
456  return count;
457  }
458 
459  // DerivedStats for proxy groups cannot be re-configured
460  // at InitGenerator time or from Introspect
461  // The Proxy group configuration should be changed instead
463  const std::map<std::string,std::string> & dsconf) {
464  return (nativep_->InitDerivedStats(dsconf));
465  }
466 
467  // Send the given UVE, for the native UVE Type map, as
468  // well as proxy groups
469  bool SendUVE(const std::string& table, const std::string& name,
470  const std::string& ctx) const {
471  bool sent = false;
472  std::vector<uve_emap *> nev =
473  const_cast<SandeshUVEPerTypeMapGroup<T,U,P,TM> * >(this)->GetNMaps();
474  for (size_t idx=0; idx<nev.size(); idx++) {
475  if (nev[idx]->SendUVE(table, name, ctx)) sent = true;
476  }
477 
478  std::vector<uve_pmap *> pv =
479  const_cast<SandeshUVEPerTypeMapGroup<T,U,P,TM> * >(this)->GetGMaps();
480  for (size_t jdx=0; jdx<pv.size(); jdx++) {
481  for (size_t idx=0; idx<SandeshUVETypeMaps::kProxyPartitions; idx++) {
482  if (pv[jdx]->at(idx).SendUVE(table, name, ctx)) sent = true;
483  }
484  }
485  return sent;
486  }
487 
488  std::map<std::string, std::string> GetDSConf(void) const {
489  return nativep_->GetDSConf();
490  }
491 
492  bool UpdateUVE(U& data, uint32_t seqnum,
493  uint64_t mono_usec, int partition, SandeshLevel::type level) {
494  if (partition == -1) {
495  uve_emap *ne = GetNMap(GetNMapUVEname(data));
496  return ne->UpdateUVE(data, seqnum, mono_usec, level);
497  } else {
498  std::string proxy = SandeshStructProxyTrait<U>::get(data);
499  assert(partition < SandeshUVETypeMaps::kProxyPartitions);
500  uve_pmap * pp = GetGMap(proxy);
501  return pp->at(partition).UpdateUVE(data, seqnum, mono_usec, level);
502  }
503  }
504 
505  // Delete all UVEs for the given partition for the given proxy group
506  uint32_t ClearUVEs(const std::string& proxy, int partition) {
507  if (partition != -1) {
508  std::scoped_lock lock(gmutex_);
509  typename uve_gmap::iterator gi = group_map_.find(proxy);
510  if (gi != group_map_.end()) {
511  assert(partition < SandeshUVETypeMaps::kProxyPartitions);
512  return gi->second->at(partition).ClearUVEs();
513  }
514  }
515  return 0;
516  }
517 
518 private:
519  mutable std::mutex gmutex_;
521  mutable std::mutex nmutex_;
524 };
525 
526 #endif
std::size_t hash_value(BgpAttr const &attr)
Definition: bgp_attr.cc:1273
boost::ptr_map< int, uve_emap > uve_pmap
Definition: sandesh_uve.h:361
boost::ptr_map< string, uve_pmap > uve_gmap
Definition: sandesh_uve.h:364
string GetNMapUVEname(U &data)
Definition: sandesh_uve.h:374
SandeshUVEPerTypeMapGroup(char const *u_name)
Definition: sandesh_uve.h:366
uint32_t ClearUVEs(const std::string &proxy, int partition)
Definition: sandesh_uve.h:506
std::vector< uve_emap * > GetNMaps(void)
Definition: sandesh_uve.h:394
bool UpdateUVE(U &data, uint32_t seqnum, uint64_t mono_usec, int partition, SandeshLevel::type level)
Definition: sandesh_uve.h:492
std::vector< uve_pmap * > GetGMaps(void)
Definition: sandesh_uve.h:419
uint32_t SyncUVE(const std::string &table, SandeshUVE::SendType st, uint32_t seqno, uint32_t cycle, const std::string &ctx)
Definition: sandesh_uve.h:440
uve_emap * GetNMap(const std::string &name)
Definition: sandesh_uve.h:380
bool SendUVE(const std::string &table, const std::string &name, const std::string &ctx) const
Definition: sandesh_uve.h:469
boost::ptr_map< string, uve_emap > uve_nmap
Definition: sandesh_uve.h:358
uint32_t TypeSeq(void) const
Definition: sandesh_uve.h:431
std::map< std::string, std::string > GetDSConf(void) const
Definition: sandesh_uve.h:488
int GetTimeout(void) const
Definition: sandesh_uve.h:435
uve_pmap * GetGMap(const std::string &proxy)
Definition: sandesh_uve.h:405
bool InitDerivedStats(const std::map< std::string, std::string > &dsconf)
Definition: sandesh_uve.h:462
SandeshUVEPerTypeMapImpl< T, U, P, TM > uve_emap
Definition: sandesh_uve.h:355
bool InitDerivedStats(const std::map< std::string, std::string > &dsconf)
Definition: sandesh_uve.h:227
uint32_t ClearUVEs(void)
Definition: sandesh_uve.h:199
uint32_t SyncUVE(const std::string &table, SandeshUVE::SendType st, uint32_t seqno, uint32_t cycle, const std::string &ctx)
Definition: sandesh_uve.h:271
tbb::concurrent_hash_map< std::string, uve_table_map, HashCompare > uve_cmap
Definition: sandesh_uve.h:134
std::map< std::string, std::string > GetDSConf(void) const
Definition: sandesh_uve.h:338
bool UpdateUVE(U &data, uint32_t seqnum, uint64_t mono_usec, SandeshLevel::type level)
Definition: sandesh_uve.h:142
std::map< std::string, std::string > dsconf_
Definition: sandesh_uve.h:345
bool SendUVE(const std::string &table, const std::string &name, const std::string &ctx) const
Definition: sandesh_uve.h:321
boost::ptr_map< std::string, UVEMapEntry > uve_table_map
Definition: sandesh_uve.h:131
virtual bool InitDerivedStats(const std::map< std::string, std::string > &dsconf)=0
virtual int GetTimeout(void) const =0
virtual uint32_t ClearUVEs(const std::string &proxy, int partition)=0
virtual ~SandeshUVEPerTypeMap()
Definition: sandesh_uve.h:78
virtual uint32_t TypeSeq() const =0
virtual bool SendUVE(const std::string &table, const std::string &name, const std::string &ctx) const =0
virtual std::map< std::string, std::string > GetDSConf(void) const =0
virtual uint32_t SyncUVE(const std::string &table, SandeshUVE::SendType st, uint32_t seqno, uint32_t cycle, const std::string &ctx)=0
static uve_global_map::const_iterator Begin()
Definition: sandesh_uve.h:59
static bool InitDerivedStats(const std::map< std::string, ds_conf_elem > &)
Definition: sandesh_uve.cc:25
static uve_global_map * map_
Definition: sandesh_uve.h:63
std::map< std::string, std::string > ds_conf_elem
Definition: sandesh_uve.h:38
static uve_global_map * GetMap()
Definition: sandesh_uve.h:65
std::pair< int, SandeshUVEPerTypeMap * > uve_global_elem
Definition: sandesh_uve.h:36
std::map< std::string, uve_global_elem > uve_global_map
Definition: sandesh_uve.h:37
static const uve_global_elem TypeMap(const std::string &s)
Definition: sandesh_uve.h:45
static void RegisterType(const std::string &s, SandeshUVEPerTypeMap *tmap, int period)
Definition: sandesh_uve.h:40
static const int kProxyPartitions
Definition: sandesh_uve.h:61
static uve_global_map::const_iterator End()
Definition: sandesh_uve.h:60
static void SyncAllMaps(const std::map< std::string, uint32_t > &, bool periodic=false)
Definition: sandesh_uve.cc:60
static void SyncIntrospect(std::string tname, std::string table, std::string key)
Definition: sandesh_uve.cc:92
static uint32_t Clear(const std::string &proxy, int partition)
Definition: sandesh_uve.cc:44
#define SANDESH_LOG(_Level, _Msg)
Definition: cpp/sandesh.h:476
uint8_t type
Definition: load_balance.h:2
void failure(const char *fmt,...)
static std::string get(const T &s)
Definition: cpp/sandesh.h:687
static size_t hash(const std::string &key)
Definition: sandesh_uve.h:114
static bool equal(const std::string &key1, const std::string &key2)
Definition: sandesh_uve.h:116
UVEMapEntry(const std::string &table, uint32_t seqnum, SandeshLevel::type level)
Definition: sandesh_uve.h:121
static uint64_t ClockMonotonicUsec()
Definition: time_util.h:29