OpenSDN source code
db_table_partition.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include "base/logging.h"
7 #include "base/time_util.h"
8 #include "db/db.h"
9 #include "db/db_entry.h"
10 #include "db/db_partition.h"
11 #include "db/db_table.h"
12 #include "db/db_table_partition.h"
13 
14 using namespace std;
15 
16 // concurrency: called from DBPartition task.
18  if (entry->is_onlist()) {
19  return;
20  }
21  entry->set_onlist();
22  bool was_empty = change_list_.empty();
23  change_list_.push_back(*entry);
24  if (was_empty) {
25  DB *db = parent()->database();
26  DBPartition *partition = db->GetPartition(index_);
27  partition->OnTableChange(this);
28  }
29 }
30 
31 //
32 // Concurrency: called from db::DBTable/db::IFMapTable task.
33 //
34 // Evaluate concurrency issues with DBEntryBase::ClearState when making
35 // changes to this method. We expect that either this method or ClearState
36 // is responsible for removing the DBEntryBase when they run concurrently,
37 // assuming the DBEntryBase is eligible for removal. The dbstate_mutex is
38 // used for synchronization.
39 //
41  for (int i = 0; ((i < kMaxIterations) && !change_list_.empty()); ++i) {
42  DBEntryBase *entry = &change_list_.front();
43  change_list_.pop_front();
44 
45  parent()->RunNotify(this, entry);
46  entry->clear_onlist();
47 
48  // If the entry is marked deleted and all DBStates are removed
49  // and it's not already on the remove queue, it can be removed
50  // from the tree right away.
51  //
52  // Note that IsOnRemoveQ must be called after is_state_empty as
53  // synchronization with DBEntryBase::ClearState happens via the
54  // call to is_state_empty, and ClearState can set the OnRemoveQ
55  // bit in the entry.
56  if (entry->IsDeleted() && entry->is_state_empty(this) &&
57  !entry->IsOnRemoveQ()) {
58  Remove(entry);
59  }
60  }
61 
62  if (!change_list_.empty()) {
63  DB *db = parent()->database();
64  DBPartition *partition = db->GetPartition(index_);
65  partition->OnTableChange(this);
66  return false;
67  }
68  return true;
69 }
70 
72  if (parent_->HasListeners()) {
73  entry->MarkDelete();
74  Notify(entry);
75  } else {
76  // Remove from change_list
77  if (entry->is_onlist()) {
78  change_list_.erase(change_list_.iterator_to(*entry));
79  }
80  Remove(entry);
81  }
82 }
83 
85  : DBTablePartBase(table, index) {
86 }
87 
89  DBTable *table = static_cast<DBTable *>(parent());
91  table->Input(this, client, req);
92 }
93 
95  std::scoped_lock lock(mutex_);
96  std::pair<Tree::iterator, bool> ret = tree_.insert(*entry);
97  assert(ret.second);
98  entry->set_table_partition(static_cast<DBTablePartBase *>(this));
99  Notify(entry);
100  parent()->AddRemoveCallback(entry, true);
101 }
102 
104  std::scoped_lock lock(mutex_);
105  Notify(entry);
106 }
107 
109  std::scoped_lock lock(mutex_);
110  DBEntry *entry = static_cast<DBEntry *>(db_entry);
111  parent()->AddRemoveCallback(entry, false);
112 
113  bool success = tree_.erase(*entry);
114  if (!success) {
115  LOG(FATAL, "ABORT: DB node erase failed for table " + parent()->name());
116  LOG(FATAL, "Invalid node " + db_entry->ToString());
117  abort();
118  }
119  delete entry;
120 
121  // If a table is marked for deletion, then we may trigger the deletion
122  // process when the last prefix is deleted
123  if (tree_.empty())
124  table()->RetryDelete();
125 }
126 
128  std::scoped_lock lock(mutex_);
129  tree_.insert(*entry);
130  entry->set_table_partition(static_cast<DBTablePartBase *>(this));
131  Notify(entry);
132  parent()->AddRemoveCallback(entry, true);
133 }
134 
136  std::scoped_lock lock(mutex_);
137  bool success = tree_.erase(*entry);
138  if (!success) {
139  LOG(FATAL, "ABORT: DB node erase failed for table " + parent()->name());
140  abort();
141  }
142 }
143 
145  Tree::iterator loc = tree_.find(*entry);
146  if (loc != tree_.end()) {
147  return loc.operator->();
148  }
149  return NULL;
150 }
151 
152 const DBEntry *DBTablePartition::FindInternal(const DBEntry *entry) const {
153  Tree::const_iterator loc = tree_.find(*entry);
154  if (loc != tree_.end()) {
155  return loc.operator->();
156  }
157  return NULL;
158 }
159 
161  CHECK_CONCURRENCY("db::DBTable", "db::IFMapTable",
162  "Agent::FlowEvent", "Agent::FlowUpdate");
163  return FindInternal(entry);
164 }
165 
167  std::scoped_lock lock(mutex_);
168  return FindInternal(entry);
169 }
170 
171 const DBEntry *DBTablePartition::Find(const DBEntry *entry) const {
172  std::scoped_lock lock(mutex_);
173  return FindInternal(entry);
174 }
175 
177  CHECK_CONCURRENCY("db::DBTable", "db::IFMapTable",
178  "Agent::FlowEvent", "Agent::FlowUpdate");
179  DBTable *table = static_cast<DBTable *>(parent());
180  std::unique_ptr<DBEntry> entry_ptr = table->AllocEntry(key);
181  return FindInternal(entry_ptr.get());
182 }
183 
185  DBTable *table = static_cast<DBTable *>(parent());
186  std::unique_ptr<DBEntry> entry_ptr = table->AllocEntry(key);
187  std::scoped_lock lock(mutex_);
188  return FindInternal(entry_ptr.get());
189 }
190 
192  std::scoped_lock lock(mutex_);
193  DBTable *table = static_cast<DBTable *>(parent());
194  std::unique_ptr<DBEntry> entry_ptr = table->AllocEntry(key);
195 
196  Tree::iterator loc = tree_.upper_bound(*(entry_ptr.get()));
197  if (loc != tree_.end()) {
198  return loc.operator->();
199  }
200  return NULL;
201 }
202 
203 // Returns the matching entry or next in lex order
205  const DBEntry *entry = static_cast<const DBEntry *>(key);
206  std::scoped_lock lock(mutex_);
207 
208  Tree::iterator it = tree_.lower_bound(*entry);
209  if (it != tree_.end()) {
210  return (it.operator->());
211  }
212  return NULL;
213 }
214 
216  std::scoped_lock lock(mutex_);
217  Tree::iterator it = tree_.begin();
218  if (it == tree_.end()) {
219  return NULL;
220  }
221  return it.operator->();
222 }
223 
224 // Returns the next entry (Doesn't search). Threaded walk
226  const DBEntry *entry = static_cast<const DBEntry *>(key);
227  std::scoped_lock lock(mutex_);
228 
229  Tree::const_iterator it = tree_.iterator_to(*entry);
230  it++;
231  if (it != tree_.end()) {
232  return const_cast<DBEntry *>(it.operator->());
233  }
234  return NULL;
235 }
236 
238  return static_cast<DBTable *>(parent());
239 }
void MarkDelete()
Definition: db_entry.h:46
virtual std::string ToString() const =0
bool IsOnRemoveQ()
Definition: db_entry.h:57
void set_onlist()
Definition: db_entry.h:50
bool IsDeleted() const
Definition: db_entry.h:48
bool is_onlist()
Definition: db_entry.h:52
bool is_state_empty(DBTablePartBase *tpart)
Definition: db_entry.cc:87
void set_table_partition(DBTablePartBase *tpart)
Definition: db_entry.cc:111
void clear_onlist()
Definition: db_entry.h:51
void OnTableChange(DBTablePartBase *tpart)
void incr_input_count()
Definition: db_table.h:121
virtual void RetryDelete()
Definition: db_table.h:104
virtual void AddRemoveCallback(const DBEntryBase *entry, bool add) const
Definition: db_table.h:84
DBTableBase * parent()
void Notify(DBEntryBase *entry)
void Delete(DBEntryBase *)
virtual void Change(DBEntry *entry)
void Process(DBClient *client, DBRequest *req)
virtual void Add(DBEntry *entry)
void RemoveWithoutDelete(DBEntry *entry)
DBEntry * FindNext(const DBRequestKey *key)
DBEntry * FindInternal(const DBEntry *entry)
DBEntry * FindNoLock(const DBEntry *entry)
DBTablePartition(DBTable *parent, int index)
virtual DBEntry * GetNext(const DBEntryBase *entry)
void AddWithoutAlloc(DBEntry *entry)
virtual DBEntry * lower_bound(const DBEntryBase *entry)
DBEntry * Find(const DBEntry *entry)
virtual void Remove(DBEntryBase *entry)
virtual DBEntry * GetFirst()
virtual std::unique_ptr< DBEntry > AllocEntry(const DBRequestKey *key) const =0
virtual void Input(DBTablePartition *tbl_partition, DBClient *client, DBRequest *req)
Definition: db_table.cc:542
Definition: db.h:24
DBPartition * GetPartition(int index)
Definition: db.cc:60
#define LOG(_Level, _Msg)
Definition: logging.h:34
#define CHECK_CONCURRENCY(...)