Choosing an API

    +
    Async & batching

    Libcouchbase is an asynchronous client that may also be used in blocking mode. The library contains I/O plugins for common libraries such as libevent, libev, and libuv, and a libevent-based example can be found here.

    Batching examples are given for bulk store and for bulk get.

    Usage Differences in Non-Blocking Mode

    For the most part, programming with libcouchbase is the same regardless of whether you’re using it in a blocking or non-blocking application. There are some key differences to note, however:

    • lcb_wait() should not be called in non-blocking mode. By definition, the lcb_wait() routine will block the application until all pending I/O completes. In non-blocking mode the pending I/O is completed when control is returned back to the event loop.

    • You must not schedule operations until the bootstrap callback, lcb_set_bootstrap_callback(), has been invoked. This is because operations must be forwarded to a destination node in the cluster depending on the key specified within the operation. Until the client has been bootstrapped it does not know how to forward keys to any nodes.

      Unlike blocking mode where you may simply do:

      lcb_connect(instance);
      lcb_wait(instance);
      if (lcb_get_bootstrap_status(instance) == LCB_SUCCESS)) {
        // Start operations
      }

      You need to use the callback variant that notifies your application when the library is ready.

    • You are responsible for ensuring that the iops structure passed to the library remains valid until lcb_destroy is invoked. Likewise, you are responsible for freeing the iops structure via lcb_destroy_io_opts() when it is no longer required.

    • Currently the library does blocking DNS look-ups via the standard getaddrinfo() call. Typically this should not take a long time but may potentially block your application if an invalid host name is detected or the DNS server in use is slow to respond.

    Batching

    The most simplistic bulk fetch looks like this:

        // Make a list of keys to store initially
        std::vector<std::string> keys_to_get{ "foo", "bar", "baz" };
    
        std::vector<Result> results;
        results.reserve(keys_to_get.size());
    
        lcb_sched_enter(instance);
        for (const auto& key : keys_to_get) {
            lcb_CMDGET* cmd = nullptr;
            check(lcb_cmdget_create(&cmd), "create GET command");
            check(lcb_cmdget_key(cmd, key.c_str(), key.size()), "assign ID for GET command");
            lcb_STATUS rc = lcb_get(instance, &results, cmd);
            check(lcb_cmdget_destroy(cmd), "destroy GET command");
            if (rc != LCB_SUCCESS) {
                std::cerr << "[ERROR] could not schedule GET for " << key << ": " << lcb_strerror_short(rc) << "\n";
                // Discards all operations since the last scheduling context (created by lcb_sched_enter)
                lcb_sched_fail(instance);
                break;
            }
        }
        lcb_sched_leave(instance);
        check(lcb_wait(instance, LCB_WAIT_DEFAULT), "wait for batch to complete");