OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
feature_flags.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include <string>
6 #include <base/feature_flags.h>
7 #include <assert.h>
8 #include <map>
9 #include <iostream>
10 #include <sstream>
11 
12 using namespace std;
13 using contrail_rapidjson::Document;
14 using contrail_rapidjson::Value;
15 
16 namespace process {
17 
18 bool debug_ = true;
19 
20 #define FLAG_DEBUG(args...) if (process::debug_) LOG(DEBUG, ##args)
21 #define FLAG_WARN(args...) if (process::debug_) LOG(WARN, ##args)
22 #define FLAG_ERROR(args...) if (process::debug_) LOG(ERROR, ##args)
23 
33 Flag::Flag(FlagManager *manager, const string &name,
34  const string &description, bool enabled,
35  ContextVec &context_infos)
36  : name_(name),
37  description_(description),
38  enabled_(enabled),
39  context_infos_(context_infos),
40  flag_state_cb_(NULL),
41  manager_(manager)
42 {
46  manager_->Register(this);
47 }
48 
49 Flag::Flag(const Flag& flag, FlagStateCb callback)
50  : name_(flag.name_),
51  description_(flag.description_),
52  enabled_(flag.enabled_),
53  context_infos_(flag.context_infos_),
54  flag_state_cb_(callback),
55  manager_(flag.manager_)
56 {
60  manager_->Register(this);
61 }
62 
64  if (manager_) {
65  manager_->Unregister(this);
66  }
67 }
68 
74  if (!flag_state_cb_.empty()) {
76  }
77 }
78 
79 bool Flag::operator == (const Flag &rhs) const {
80  if (!(name_ == rhs.name_))
81  return false;
82  if (!(description_ == rhs.description_))
83  return false;
84  if (!(enabled_ == rhs.enabled_))
85  return false;
86  if (!(context_infos_ == rhs.context_infos_))
87  return false;
88  return true;
89 }
90 
91 bool Flag::operator != (const Flag &rhs) const {
92  return !(*this == rhs);
93 }
94 
101 boost::scoped_ptr<FlagUveManager> FlagUveManager::instance_;
102 
104  FlagUveCb flag_uve_cb)
105  : flag_manager_(manager),
106  flag_uve_cb_(flag_uve_cb) {
107 }
108 
113  FlagUveCb flag_uve_cb) {
118  assert(instance_ == NULL);
119  instance_.reset(new FlagUveManager(manager, flag_uve_cb));
120 }
121 
123  if (instance_ == NULL) {
124  instance_.reset(new FlagUveManager(NULL, NULL));
125  }
126  return instance_.get();
127 }
128 
130  if (!flag_uve_cb_.empty()) {
131  flag_uve_cb_();
132  } else {
133  FLAG_WARN("SendUVE cb not set");
134  }
135 }
136 
138  if (lock) {
139  return (flag_manager_->GetFlagInfos());
140  } else {
142  }
143 }
144 
154 boost::scoped_ptr<FlagConfigManager> FlagConfigManager::instance_;
156 
158  : flag_manager_(manager) {
159 }
160 
164 void FlagConfigManager::Initialize(const string &build_info) {
165  if (instance_ == NULL) {
167  }
168 
169  Document d;
170  if ( d.Parse<0>(build_info.c_str()).HasParseError() ) {
171  FLAG_WARN("Parsing error");
172  } else {
173  const Value &v = d["build-info"];
174  version_ = v[0]["build-version"].GetString();
175  }
176 }
177 
179  if (instance_ == NULL) {
181  }
182  return instance_.get();
183 }
184 
185 void FlagConfigManager::Set(const string &name,
186  const string &version, bool enabled,
187  FlagState::Type state,
188  ContextVec &context_infos) {
194  if (version_ != version) {
195  FLAG_DEBUG("Flag " << name << "'s version " << version <<
196  " does not match with module version " << version_ <<
197  " Ignoring.");
198  return;
199  }
200  flag_manager_->Set(name, version, enabled, state, context_infos);
202 }
203 
204 void FlagConfigManager::Unset(const string &name) {
209  flag_manager_->Unset(name);
211 }
212 
222 boost::scoped_ptr<FlagManager> FlagManager::instance_;
223 
225  if (instance_ == NULL) {
226  instance_.reset(new FlagManager());
227  }
228  return instance_.get();
229 }
230 
232  flag_map_.clear();
233 }
234 
236  return (flag_map_.size());
237 }
238 
239 void FlagManager::Set(const string &name, const string &version,
240  bool enabled, FlagState::Type state,
241  ContextVec &context_infos) {
246  context_iterator c_itr;
247  bool changed = false;
248 
249  FlagConfig flag_cfg(name, version, enabled, state, context_infos);
250 
251  tbb::mutex::scoped_lock lock(mutex_);
252  flag_map_itr fmap_itr = flag_map_.find(name);
253  if (fmap_itr != flag_map_.end()) {
258  FlagConfig old_cfg = fmap_itr->second;
259 
260  FLAG_DEBUG("Flag " << name << "Already Present\n");
261  FLAG_DEBUG(" EXISTING INFO:\n "
262  << " Version: " << old_cfg.version()
263  << " Enabled: " << string(old_cfg.enabled() ? "True " : "False ")
264  << " State: " << FlagState::ToString(old_cfg.state()));
265  const ContextVec c_vec = old_cfg.context_infos();
266  FLAG_DEBUG("Context Info: ");
267  for (c_itr = c_vec.begin(); c_itr != c_vec.end(); ++c_itr) {
268  FLAG_DEBUG("Description: " << c_itr->desc
269  << " Value: " << c_itr->value);
270  }
271 
272  if (old_cfg != flag_cfg) {
273  FLAG_DEBUG("Flag " << name << " updated\n");
274  changed = true;
275  fmap_itr->second = flag_cfg;
276  } else {
277  FLAG_DEBUG("No change in flag " << name << " configuration\n");
278  }
279  } else {
283  changed = true;
284  FLAG_DEBUG("New flag configured. Name: " << name);
285  flag_map_.insert(make_pair(name, flag_cfg));
286  }
287 
288  FLAG_DEBUG(" NEW INFO:\n "
289  << " Version: " << flag_cfg.version()
290  << " Enabled: " << string(flag_cfg.enabled() ? "True " : "False ")
291  << " State: " << FlagState::ToString(flag_cfg.state()));
292  const ContextVec c_vec = flag_cfg.context_infos();
293  FLAG_DEBUG("Context Info: ");
294  for (c_itr = c_vec.begin(); c_itr != c_vec.end(); ++c_itr) {
295  FLAG_DEBUG("Description: " << c_itr->desc
296  << " Value: " << c_itr->value);
297  }
298 
307  if (changed) {
308  bool enabled;
309  pair <int_map_itr, int_map_itr> ret;
310  ret = int_map_.equal_range(name);
311  for (int_map_itr it = ret.first; it != ret.second; ++it) {
312  enabled = false;
313  Flag *f = it->second;
314  enabled = IsFlagEnabled(name, f->enabled(), f->context_infos());
315  f->set_enabled(enabled);
316  f->InvokeCb();
317  }
318  }
319 }
320 
321 void FlagManager::Unset(const string &name) {
325  flag_map_.erase(name);
326 
330  pair <int_map_itr, int_map_itr> ret;
331  ret = int_map_.equal_range(name);
332  for (int_map_itr it = ret.first; it != ret.second; ++it) {
333  Flag *f = it->second;
334  f->set_enabled(false);
335  f->InvokeCb();
336  }
337 }
338 
352 bool FlagManager::IsFlagEnabled(const string &name,
353  bool default_state,
354  const ContextVec &c_vec) const {
355  flag_map_citr fitr;
356  bool result = false;
357  context_iterator c_itr, f_itr;
358 
359  FLAG_DEBUG("Checking if flag with name: " << name
360  << " is enabled for context");
361  for (c_itr = c_vec.begin(); c_itr != c_vec.end(); ++c_itr) {
362  FLAG_DEBUG("Description: " << c_itr->desc
363  << " Value: " << c_itr->value);
364  }
365 
366  fitr = flag_map_.find(name);
367  if (fitr != flag_map_.end()) {
371  FlagConfig flag_cfg = fitr->second;
372 
376  if (flag_cfg.enabled()) {
377  result = true;
378  }
379 
383  const ContextVec f_vec = flag_cfg.context_infos();
384  if (c_vec.empty() && !f_vec.empty()) {
385  result = false;
386  }
387  for (c_itr = c_vec.begin(); c_itr != c_vec.end(); ++c_itr) {
388  f_itr = find(f_vec.begin(), f_vec.end(), *c_itr);
389  if (f_itr == f_vec.end()) {
393  result = false;
394  }
395  }
396  } else {
401  result = default_state;
402  }
403 
404  FLAG_DEBUG("Flag enabled: " << string(result ? "True" : "False"));
405 
406  return result;
407 }
408 
410  int_map_itr itr;
411  flag_map_citr fitr;
412 
413  tbb::mutex::scoped_lock lock(mutex_);
414 
415  string name = flag->name();
416 
417  FLAG_DEBUG("Module interested in flag. Name: " << name <<
418  " \nAdding to InterestMap");
419 
425  fitr = flag_map_.find(name);
426  if (fitr != flag_map_.end()) {
427  FLAG_DEBUG("Flag Name: " << name <<
428  " already present in FlagMap");
429  bool value = IsFlagEnabled(name, flag->enabled(),
430  flag->context_infos());
431  flag->set_enabled(value);
432  flag->InvokeCb();
433  }
434 
438  itr = int_map_.insert(make_pair(name, flag));
439 }
440 
441 void FlagManager::Unregister(const Flag *flag) {
442  pair <int_map_itr, int_map_itr> ret;
443  const string name = flag->name();
444  ret = int_map_.equal_range(name);
445 
446  FLAG_DEBUG("Module not interested in flag. Name: " << name <<
447  " \nRemoving from InterestMap");
448 
449  tbb::mutex::scoped_lock lock(mutex_);
450 
451  int_map_itr it = ret.first;
452  while (it != ret.second) {
453  if (it->second == flag) {
454  int_map_.erase(it);
455  break;
456  } else {
457  ++it;
458  }
459  }
460 }
461 
462 bool FlagManager::IsRegistered(const Flag *flag) const {
463  pair <int_map_const_itr, int_map_const_itr> ret;
464 
465  tbb::mutex::scoped_lock lock(mutex_);
466 
467  ret = int_map_.equal_range(flag->name());
468  for (int_map_const_itr it = ret.first; it != ret.second; ++it) {
469  if (it->second == flag) {
470  return true;
471  }
472  }
473  return false;
474 }
475 
477  return (int_map_.size());
478 }
479 
481  flag_map_citr fitr;
482  int_map_const_itr iitr;
483  FlagConfigVec flag_infos;
484 
489  for (fitr = flag_map_.begin(); fitr != flag_map_.end(); ++fitr) {
490  FlagConfig flag_cfg = fitr->second;
491  iitr = int_map_.find(flag_cfg.name());
492  if (iitr != int_map_.end()) {
493  flag_infos.push_back(flag_cfg);
494  }
495  }
496 
497  return flag_infos;
498 }
499 
501  tbb::mutex::scoped_lock lock(mutex_);
502  return GetFlagInfosUnlocked();
503 }
504 
505 } // namespace process
const FlagState::Type & state() const
static void Initialize(const string &build_info)
const std::string & version() const
void Unset(const std::string &name)
std::string description_
void Set(const std::string &name, const std::string &version, bool enabled, FlagState::Type state, ContextVec &context_infos)
static FlagUveManager * GetInstance()
static boost::scoped_ptr< FlagUveManager > instance_
size_t GetIntMapCount() const
void Unset(const std::string &name)
std::string name_
bool enabled() const
static FlagConfigManager * GetInstance()
std::map< std::string, FlagConfig >::const_iterator flag_map_citr
ContextVec context_infos_
FlagConfigVec GetFlagInfos() const
static std::string ToString(Type state)
void Unregister(const Flag *flag)
const ContextVec & context_infos() const
boost::function< void(void)> FlagUveCb
void Register(Flag *flag)
FlagManager * flag_manager_
std::multimap< std::string, Flag * >::const_iterator int_map_const_itr
const bool enabled() const
size_t GetFlagMapCount() const
#define FLAG_DEBUG(args...)
std::map< std::string, FlagConfig >::iterator flag_map_itr
void Set(const std::string &name, const std::string &version_info, bool enabled, FlagState::Type state, ContextVec &context_infos)
static FlagManager * GetInstance()
bool debug_
FlagConfigVec GetFlagInfosUnlocked() const
std::vector< FlagConfig > FlagConfigVec
void set_enabled(const bool val)
static void CreateInstance(FlagManager *mgr, FlagUveCb send_uve_cb)
FlagConfigVec GetFlagInfos(bool lock) const
const ContextVec & context_infos() const
FlagStateCb flag_state_cb_
std::multimap< std::string, Flag * >::iterator int_map_itr
bool operator==(const Flag &rhs) const
static std::string version_
bool IsRegistered(const Flag *flag) const
bool operator!=(const Flag &rhs) const
const std::string & name() const
FlagUveManager(FlagManager *manager, FlagUveCb send_uve_cb)
boost::function< void()> FlagStateCb
std::vector< FlagContext > ContextVec
std::vector< FlagContext >::const_iterator context_iterator
static boost::scoped_ptr< FlagManager > instance_
bool IsFlagEnabled(const std::string &name, bool default_state, const ContextVec &c_vec) const
FlagConfigManager(FlagManager *manager)
FlagManager * manager_
static boost::scoped_ptr< FlagConfigManager > instance_
const std::string & name() const
#define FLAG_WARN(args...)