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