LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/zookeeper - zookeeper_client.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 133 258 51.6 %
Date: 2026-11-09 02:10:49 Functions: 25 49 51.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //
       2             : // Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
       3             : // Copyright Contributors to the OpenSDN project
       4             : //
       5             : 
       6             : #include <cerrno>
       7             : #include <cstring>
       8             : 
       9             : #include <base/logging.h>
      10             : 
      11             : #include <zookeeper/zookeeper_client.h>
      12             : #include <zookeeper/zookeeper_client_impl.h>
      13             : #include <zookeeper/zookeeper_interface.h>
      14             : 
      15             : #define ZOO_LOG(_Level, _Msg)                                             \
      16             :     do {                                                                  \
      17             :         if (LoggingDisabled()) break;                                     \
      18             :         log4cplus::Logger logger = log4cplus::Logger::getRoot();          \
      19             :         LOG4CPLUS_##_Level(logger, __func__ << ":" << __FILE__ << ":" <<  \
      20             :             __LINE__ << ": " << _Msg);                                    \
      21             :     } while (false)
      22             : 
      23             : #define ZOO_LOG_ERR(_Msg)                                                 \
      24             :     do {                                                                  \
      25             :         LOG(ERROR, __func__ << ":" << __FILE__ << ":" << __LINE__ << ": " \
      26             :             << _Msg);                                                     \
      27             :     } while (false)
      28             : 
      29             : namespace zookeeper {
      30             : namespace interface {
      31             : 
      32             : class ZookeeperCBindings : public ZookeeperInterface {
      33             :  public:
      34           0 :     ZookeeperCBindings() {
      35           0 :     }
      36           0 :     virtual ~ZookeeperCBindings() {
      37           0 :     }
      38           0 :     virtual void ZooSetDebugLevel(ZooLogLevel logLevel) {
      39           0 :         zoo_set_debug_level(logLevel);
      40           0 :     }
      41           0 :     virtual zhandle_t* ZookeeperInit(const char *host, watcher_fn fn,
      42             :         int recv_timeout, const clientid_t *clientid, void *context,
      43             :         int flags) {
      44           0 :         return zookeeper_init(host, fn, recv_timeout, clientid, context,
      45           0 :             flags);
      46             :     }
      47           0 :     virtual int ZookeeperClose(zhandle_t *zh) {
      48           0 :         return zookeeper_close(zh);
      49             :     }
      50           0 :     virtual int ZooState(zhandle_t *zh) {
      51           0 :         return zoo_state(zh);
      52             :     }
      53           0 :     virtual int ZooCreate(zhandle_t *zh, const char *path, const char *value,
      54             :         int valuelen, const struct ACL_vector *acl, int flags,
      55             :         char *path_buffer, int path_buffer_len) {
      56           0 :         return zoo_create(zh, path, value, valuelen, acl, flags, path_buffer,
      57           0 :             path_buffer_len);
      58             :     }
      59           0 :     virtual int ZooDelete(zhandle_t *zh, const char *path, int version) {
      60           0 :         return zoo_delete(zh, path, version);
      61             :     }
      62           0 :     virtual int ZooGet(zhandle_t *zh, const char *path, int watch,
      63             :         char *buffer, int* buffer_len, struct Stat *stat) {
      64           0 :         return zoo_get(zh, path, watch, buffer, buffer_len, stat);
      65             :     }
      66           0 :     virtual int ZooExists(zhandle_t *zh, const char *path, int watch,
      67             :                                          struct Stat *stat) {
      68           0 :         return zoo_exists(zh, path, watch, stat);
      69             :     }
      70           0 :     virtual void ZooSetContext(zhandle_t * zh, void *context) {
      71           0 :         return zoo_set_context(zh, context);
      72             :     }
      73           0 :     virtual int ZooIsUnrecoverable(zhandle_t * zh) {
      74           0 :         return is_unrecoverable(zh);
      75             :     }
      76             : };
      77             : 
      78             : } // namespace interface
      79             : 
      80             : namespace client {
      81             : namespace impl {
      82             : 
      83           0 : void ZookeeperWatcher(zhandle_t* zh, int type, int state,
      84             :         const char* path, void* watcherCtx) {
      85           0 :     if (ZINVALIDSTATE == is_unrecoverable(zh)) {
      86           0 :         ZOO_LOG(DEBUG, "Zookeeper callback called with state " << state);
      87           0 :         ZookeeperClientImpl *zooImpl = (ZookeeperClientImpl *)watcherCtx;
      88           0 :         if (zooImpl && zooImpl->GetClient()) {
      89           0 :             if (((ZookeeperClient *)zooImpl->GetClient())->cb) {
      90           0 :                 ((ZookeeperClient *)zooImpl->GetClient())->cb();
      91             :             }
      92             :         }
      93             :     }
      94           0 : }
      95             : 
      96             : // ZookeeperClientImpl
      97           6 : ZookeeperClientImpl::ZookeeperClientImpl(const char *hostname,
      98           6 :     const char *servers, zookeeper::interface::ZookeeperInterface *zki) :
      99           6 :     hostname_(hostname),
     100           6 :     servers_(servers),
     101           6 :     zk_handle_(NULL),
     102           6 :     connected_(false),
     103          12 :     zki_(zki) {
     104             :     // Set loglevel
     105           6 :     zki_->ZooSetDebugLevel(ZOO_LOG_LEVEL_DEBUG);
     106           6 : }
     107             : 
     108          12 : ZookeeperClientImpl::~ZookeeperClientImpl() {
     109          12 : }
     110             : 
     111           7 : bool ZookeeperClientImpl::Connect() {
     112             :     while (true) {
     113           7 :         zk_handle_ = zki_->ZookeeperInit(servers_.c_str(),
     114             :                                          ZookeeperWatcher,
     115             :                                          kSessionTimeoutMSec_,
     116             :                                          NULL,
     117             :                                          NULL,
     118             :                                          0);
     119           7 :         if (zk_handle_ == NULL) {
     120           0 :             int zerrno(errno);
     121           0 :             ZOO_LOG_ERR("zookeeper_init FAILED: (" << zerrno <<
     122             :                 "): servers: " << servers_ << " retrying in 1 second");
     123           0 :             sleep(1);
     124           0 :             continue;
     125           0 :         }
     126           7 :         zki_->ZooSetContext(zk_handle_, this);
     127             :         // Block till session is connected
     128           8 :         while (!connected_) {
     129           8 :             int zstate(zki_->ZooState(zk_handle_));
     130           8 :             if (zstate == ZOO_CONNECTED_STATE) {
     131           7 :                 connected_ = true;
     132           7 :                 ZOO_LOG(DEBUG, "Session CONNECTED");
     133           7 :                 break;
     134             :             } else {
     135           1 :                 ZOO_LOG(DEBUG, "Session NOT CONNECTED: retrying in 1 second");
     136           1 :                 sleep(1);
     137           1 :                 continue;
     138           1 :             }
     139             :         }
     140           7 :         break;
     141           0 :     }
     142           7 :     assert(connected_);
     143           7 :     return true;
     144             : }
     145             : 
     146           7 : void ZookeeperClientImpl::Shutdown() {
     147           7 :     if (zk_handle_) {
     148           7 :         int rc(zki_->ZookeeperClose(zk_handle_));
     149           7 :         if (rc != ZOK) {
     150           0 :             int zerrno(errno);
     151           0 :             ZOO_LOG(WARN, "zookeeper_close FAILED (" << rc <<
     152             :                 "): errno: " << zerrno);
     153             :         }
     154           7 :         zk_handle_ = NULL;
     155             :     }
     156           7 :     connected_ = false;
     157           7 : }
     158             : 
     159           1 : bool ZookeeperClientImpl::Reconnect() {
     160           1 :     Shutdown();
     161           1 :     return Connect();
     162             : }
     163             : 
     164          19 : bool ZookeeperClientImpl::IsConnected() const {
     165          19 :     return connected_;
     166             : }
     167             : 
     168          20 : static inline bool IsZooErrorRecoverable(int zerror) {
     169          20 :     return zerror == ZCONNECTIONLOSS ||
     170          20 :         zerror == ZOPERATIONTIMEOUT;
     171             : }
     172             : 
     173          16 : static inline bool IsZooErrorUnrecoverable(int zerror) {
     174          16 :     return zerror == ZINVALIDSTATE;
     175             : }
     176             : 
     177           8 : int ZookeeperClientImpl::CreateNodeSync(const char *path, const char *value,
     178             :     int *err, int flag) {
     179             :     int rc;
     180           8 :  retry:
     181             :     do {
     182          10 :         rc = zki_->ZooCreate(zk_handle_, path, value, strlen(value),
     183             :             &ZOO_OPEN_ACL_UNSAFE, flag, NULL, -1);
     184          10 :     } while (IsZooErrorRecoverable(rc));
     185           8 :     if (IsZooErrorUnrecoverable(rc)) {
     186             :         // Reconnect
     187           1 :         Reconnect();
     188           1 :         goto retry;
     189             :     }
     190           7 :     if (rc != ZOK) {
     191           2 :         *err = errno;
     192             :     }
     193           7 :     return rc;
     194             : }
     195             : 
     196           0 : bool ZookeeperClientImpl::CreateNode(const char *path, const char *value,
     197             :                                      int flag) {
     198           0 :     int err = 0;
     199             :     int rc;
     200           0 :     if (!IsConnected()) {
     201           0 :         bool success(Connect());
     202           0 :         if (!success) {
     203           0 :             ZOO_LOG_ERR("Zookeeper Client Connect FAILED");
     204           0 :             return false;
     205             :         }
     206             :     }
     207           0 :     rc = CreateNodeSync(path, value, &err, flag);
     208           0 :     if (rc != ZOK && rc != ZNODEEXISTS) {
     209           0 :         ZOO_LOG_ERR("Creation of ZNODE(" << path << "): " << value
     210             :                     << ": FAILED: (" << rc << ") error: " << err);
     211           0 :         return false;
     212             :     }
     213           0 :     return true;
     214             : }
     215             : 
     216           2 : int ZookeeperClientImpl::GetNodeDataSync(const char *path, char *buf,
     217             :     int *buf_len, int *err) {
     218             :     int rc;
     219           2 :  retry:
     220             :     do {
     221           2 :         rc = zki_->ZooGet(zk_handle_, path, 0, buf, buf_len, NULL);
     222           2 :     } while (IsZooErrorRecoverable(rc));
     223           2 :     if (IsZooErrorUnrecoverable(rc)) {
     224             :         // Reconnect
     225           0 :         Reconnect();
     226           0 :         goto retry;
     227             :     }
     228           2 :     if (rc != ZOK) {
     229           0 :         *err = errno;
     230             :     }
     231           2 :     return rc;
     232             : }
     233             : 
     234           0 : bool ZookeeperClientImpl::CheckNodeExist(const char *path) {
     235           0 :     if (!IsConnected()) {
     236           0 :         bool success(Connect());
     237           0 :         if (!success) {
     238           0 :             ZOO_LOG_ERR("Zookeeper Client Connect FAILED");
     239           0 :             return false;
     240             :         }
     241             :     }
     242             : 
     243             :     struct Stat stat;
     244           0 :     int rc = zki_->ZooExists(zk_handle_, path, 0, &stat);
     245           0 :     return (rc == ZOK);
     246             : }
     247             : 
     248           6 : int ZookeeperClientImpl::DeleteNodeSync(const char *path, int *err) {
     249             :     int rc;
     250           6 :  retry:
     251             :     do {
     252           8 :         rc = zki_->ZooDelete(zk_handle_, path, -1);
     253           8 :     } while (IsZooErrorRecoverable(rc));
     254           6 :     if (IsZooErrorUnrecoverable(rc)) {
     255             :         // Reconnect
     256           0 :         Reconnect();
     257           0 :         goto retry;
     258             :     }
     259           6 :     if (rc != ZOK) {
     260           0 :         *err = errno;
     261             :     }
     262           6 :     return rc;
     263             : }
     264             : 
     265           0 : bool ZookeeperClientImpl::DeleteNode(const char *path) {
     266           0 :     int err = 0;
     267             :     int rc;
     268           0 :     if (!IsConnected()) {
     269           0 :         bool success(Connect());
     270           0 :         if (!success) {
     271           0 :             ZOO_LOG_ERR("Zookeeper Client Connect FAILED");
     272           0 :             return false;
     273             :         }
     274             :     }
     275             : 
     276           0 :     rc = DeleteNodeSync(path, &err);
     277           0 :     if (rc != ZOK) {
     278           0 :         ZOO_LOG_ERR("Deletion of ZNODE(" << path << "): "
     279             :                     << ": FAILED: (" << rc << ") error: " << err);
     280           0 :         return false;
     281             :     }
     282             : 
     283           0 :     return (rc == ZOK);
     284             : }
     285             : 
     286           6 : std::string ZookeeperClientImpl::Name() const {
     287           6 :     return hostname_;
     288             : }
     289             : 
     290             : } // namespace impl
     291             : 
     292             : // ZookeeperClient
     293           0 : ZookeeperClient::ZookeeperClient(const char *hostname, const char *servers) :
     294           0 :     impl_(new impl::ZookeeperClientImpl(hostname, servers,
     295           0 :         new zookeeper::interface::ZookeeperCBindings)) {
     296           0 : }
     297             : 
     298           6 : ZookeeperClient::ZookeeperClient(impl::ZookeeperClientImpl *impl) :
     299           6 :     impl_(impl) {
     300           6 : }
     301             : 
     302           0 : bool ZookeeperClient::CreateNode(const char *path, const char *value,
     303             :                                  int type) {
     304           0 :     int flag = 0;
     305           0 :     if (type == Z_NODE_TYPE_EPHEMERAL) {
     306           0 :         flag |= ZOO_EPHEMERAL;
     307             :     }
     308           0 :     if (type == Z_NODE_TYPE_SEQUENCE) {
     309           0 :         flag |= ZOO_SEQUENCE;
     310             :     }
     311           0 :     return impl_->CreateNode(path, value, flag);
     312             : }
     313             : 
     314           0 : bool ZookeeperClient::CheckNodeExist(const char *path) {
     315           0 :     return impl_->CheckNodeExist(path);
     316             : }
     317             : 
     318           0 : bool ZookeeperClient::DeleteNode(const char *path) {
     319           0 :     return impl_->DeleteNode(path);
     320             : }
     321             : 
     322           0 : void ZookeeperClient::Shutdown() {
     323           0 :     return impl_->Shutdown();
     324             : }
     325             : 
     326           0 : void ZookeeperClient::AddListener(ZooStateCallback callback) {
     327           0 :     cb = callback;
     328           0 :     if (impl_.get()) {
     329           0 :         impl_->SetClient(this);
     330             :     }
     331           0 : }
     332             : 
     333          12 : ZookeeperClient::~ZookeeperClient() {
     334          12 : }
     335             : 
     336             : // ZookeeperLockImpl
     337             : class ZookeeperLock::ZookeeperLockImpl {
     338             :  public:
     339           6 :     ZookeeperLockImpl(impl::ZookeeperClientImpl *clientImpl,
     340           6 :         const char *path) :
     341           6 :         clientImpl_(clientImpl),
     342           6 :         path_(path),
     343           6 :         is_acquired_(false) {
     344           6 :         id_ = clientImpl_->Name();
     345           6 :     }
     346             : 
     347           6 :     std::string Id() const {
     348           6 :         return id_;
     349             :     }
     350             : 
     351           6 :     bool Lock() {
     352           6 :         ZOO_LOG(INFO, "Trying (" << path_ << "): " << id_);
     353             :         while (true) {
     354             :             // Connect if not already done
     355           7 :             if (!clientImpl_->IsConnected()) {
     356           6 :                 bool success(clientImpl_->Connect());
     357           6 :                 if (!success) {
     358           0 :                     ZOO_LOG_ERR("Zookeeper Client Connect FAILED");
     359           6 :                     return success;
     360             :                 }
     361             :             }
     362             :             // Try creating the znode
     363             :             int err;
     364           7 :             int rc(clientImpl_->CreateNodeSync(path_.c_str(), id_.c_str(),
     365             :                 &err, 0));
     366           7 :             switch (rc) {
     367           5 :               case ZOK: {
     368             :                 // We acquired the lock
     369           5 :                 ZOO_LOG(INFO, "ACQUIRED (" << path_ << "): " << id_);
     370           5 :                 is_acquired_ = true;
     371           5 :                 return true;
     372             :               }
     373           2 :               case ZNODEEXISTS: {
     374             :                 // Node exists, get node data and check
     375             :                 char buf[256];
     376           2 :                 int buf_len(sizeof(buf));
     377             :                 int zerr;
     378           2 :                 int zrc(clientImpl_->GetNodeDataSync(path_.c_str(), buf,
     379             :                     &buf_len, &zerr));
     380           2 :                 if (zrc == ZOK) {
     381             :                     // Does it match our ID?
     382           2 :                     std::string mid(buf, buf_len);
     383           2 :                     if (id_ == mid) {
     384             :                         // We acquired the lock
     385           1 :                         ZOO_LOG(INFO, "ACQUIRED EEXIST (" << path_ << "): "
     386             :                             << id_);
     387           1 :                         is_acquired_ = true;
     388           1 :                         return true;
     389             :                     }
     390           1 :                     ZOO_LOG_ERR("EEXIST (" << path_ << "): " << mid <<
     391             :                         " , ours: " << id_);
     392           1 :                     sleep(1);
     393           1 :                     continue;
     394           2 :                 } else if (zrc == ZNONODE) {
     395           0 :                     ZOO_LOG(WARN, "GetNodeDataSync(" << path_ <<
     396             :                         "): Data: " << id_ <<
     397             :                         ": No Node EXISTS: retrying in 1 second");
     398           0 :                     sleep(1);
     399           0 :                     continue;
     400           0 :                 } else {
     401           0 :                     ZOO_LOG_ERR("GetNodeDataSync(" << path_ << "): " <<
     402             :                         id_ << ": FAILED: (" << zrc << ") error: " << zerr);
     403           0 :                     clientImpl_->Shutdown();
     404           0 :                     return false;
     405             :                 }
     406             :                 break;
     407             :               }
     408           0 :               default: {
     409           0 :                 ZOO_LOG_ERR("CreateNodeSync(" << path_ << "): " << id_
     410             :                     << ": FAILED: (" << rc << ") error: " << err);
     411           0 :                 clientImpl_->Shutdown();
     412           0 :                 return false;
     413             :               }
     414             :             }
     415           1 :         }
     416             :     }
     417             : 
     418           6 :     bool Release() {
     419             :         bool success;
     420             :         int err, rc;
     421           6 :         if (!is_acquired_) {
     422           0 :             ZOO_LOG_ERR("(" << path_ << "): " << id_ <<
     423             :                 ": Release WITHOUT Lock");
     424           0 :             success = false;
     425           0 :             goto cleanup;
     426             :         }
     427           6 :         is_acquired_ = false;
     428           6 :         rc = clientImpl_->DeleteNodeSync(path_.c_str(), &err);
     429           6 :         if (rc == ZOK) {
     430           6 :             ZOO_LOG(INFO, "RELEASED (" << path_ << "): " << id_);
     431           6 :             success = true;
     432           6 :             goto cleanup;
     433           0 :         } else if (rc == ZNONODE) {
     434           0 :             ZOO_LOG_ERR("DeleteNodeSync(" << path_ << "): " << id_ <<
     435             :                 ": No Node EXISTS(" << err <<
     436             :                 "): Possible concurrent execution");
     437           0 :             success = false;
     438           0 :             goto cleanup;
     439             :         } else {
     440           0 :             ZOO_LOG_ERR("DeleteNodeSync(" << path_ << "): " << id_ <<
     441             :                 ": FAILED (" << rc << "): error " << err);
     442           0 :             success = false;
     443           0 :             goto cleanup;
     444             :         }
     445           6 :      cleanup:
     446           6 :         clientImpl_->Shutdown();
     447           6 :         return success;
     448             :     }
     449             : 
     450             :  private:
     451             :     impl::ZookeeperClientImpl *clientImpl_;
     452             :     std::string path_;
     453             :     bool is_acquired_;
     454             :     std::string id_;
     455             : };
     456             : 
     457             : // ZookeeperLock
     458           6 : ZookeeperLock::ZookeeperLock(ZookeeperClient *client, const char *path) :
     459           6 :     impl_(new ZookeeperLockImpl(client->impl_.get(), path)) {
     460           6 : }
     461             : 
     462           6 : ZookeeperLock::~ZookeeperLock() {
     463           6 : }
     464             : 
     465           6 : std::string ZookeeperLock::Id() const {
     466           6 :     return impl_->Id();
     467             : }
     468             : 
     469           6 : bool ZookeeperLock::Lock() {
     470           6 :     return impl_->Lock();
     471             : }
     472             : 
     473           6 : bool ZookeeperLock::Release() {
     474           6 :     return impl_->Release();
     475             : }
     476             : 
     477             : } // namespace client
     478             : } // namespace zookeeper

Generated by: LCOV version 1.14