1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 2013-2017 Couchbase, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /*
19 * BUILD: `cc -o observe observe.c -lcouchbase`
20 * RUN: `./observe key`
21 */
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <libcouchbase/couchbase.h>
27 #include <libcouchbase/api3.h>
28
29 #define fail(msg) \
30 fprintf(stderr, "%s\n", msg); \
31 exit(EXIT_FAILURE)
32
33 #define fail2(msg, err) \
34 fprintf(stderr, "%s\n", msg); \
35 fprintf(stderr, "Error was 0x%x (%s)\n", err, lcb_strerror(NULL, err)); \
36 exit(EXIT_FAILURE)
37
38 typedef struct {
39 int master;
40 lcb_U8 status;
41 lcb_U64 cas;
42 } node_info;
43
44 typedef struct {
45 unsigned nresp;
46 node_info *nodeinfo;
47 } observe_info;
48
49 static void
observe_callback(lcb_t instance,int cbtype,const lcb_RESPBASE * rb)50 observe_callback(lcb_t instance, int cbtype, const lcb_RESPBASE *rb)
51 {
52 const lcb_RESPOBSERVE *resp = (const lcb_RESPOBSERVE*)rb;
53 observe_info *obs_info = (observe_info *)rb->cookie;
54 node_info *ni = &obs_info->nodeinfo[obs_info->nresp];
55
56 if (rb->nkey == 0) {
57 fprintf(stderr, "All nodes have replied\n");
58 return;
59 }
60
61 if (rb->rc != LCB_SUCCESS) {
62 fprintf(stderr, "Failed to observe key from node. 0x%x (%s)\n",
63 rb->rc, lcb_strerror(instance, rb->rc));
64 obs_info->nresp++;
65 return;
66 }
67
68 /* Copy over the fields we care about */
69 ni->cas = resp->cas;
70 ni->status = resp->status;
71 ni->master = resp->ismaster;
72
73 /* Increase the response counter */
74 obs_info->nresp++;
75 }
76
main(int argc,char * argv[])77 int main(int argc, char *argv[])
78 {
79 lcb_t instance;
80 lcb_error_t err;
81 lcb_CMDOBSERVE cmd = { 0 };
82 lcb_MULTICMD_CTX *mctx = NULL;
83 observe_info obs_info;
84 unsigned nservers, ii;
85 struct lcb_create_st create_options = { 0 };
86
87 if (argc < 2) {
88 fail("Requires key as argument\n"
89 "Usage: observe KEY [CONNSTRING [ PASSWORD [ USERNAME ] ] ]\n");
90 }
91 create_options.version = 3;
92 if (argc > 2) {
93 create_options.v.v3.connstr = argv[2];
94 }
95 if (argc > 3) {
96 create_options.v.v3.passwd = argv[3];
97 }
98 if (argc > 4) {
99 create_options.v.v3.username = argv[4];
100 }
101
102 if ((err = lcb_create(&instance, &create_options)) != LCB_SUCCESS) {
103 fail2("cannot create connection instance", err);
104 }
105 if ((err = lcb_connect(instance)) != LCB_SUCCESS) {
106 fail2("Couldn't schedule connection", err);
107 }
108 lcb_wait(instance);
109 if ((err = lcb_get_bootstrap_status(instance)) != LCB_SUCCESS) {
110 fail2("Couldn't get initial cluster configuration", err);
111 }
112 lcb_install_callback3(instance, LCB_CALLBACK_OBSERVE, observe_callback);
113
114 nservers = lcb_get_num_nodes(instance);
115 obs_info.nodeinfo = calloc(nservers, sizeof (*obs_info.nodeinfo));
116 obs_info.nresp = 0;
117
118 mctx = lcb_observe3_ctxnew(instance);
119 LCB_CMD_SET_KEY(&cmd, argv[1], strlen(argv[1]));
120 mctx->addcmd(mctx, (const lcb_CMDBASE*)&cmd);
121
122 printf("observing the state of '%s':\n", argv[1]);
123 if ((err = mctx->done(mctx, &obs_info)) != LCB_SUCCESS) {
124 fail2("Couldn't schedule observe request", err);
125 }
126
127 lcb_wait(instance);
128 for (ii = 0; ii < obs_info.nresp; ii++) {
129 node_info *ni = &obs_info.nodeinfo[ii];
130 fprintf(stderr, "Got status from %s node:\n", ni->master ? "master" : "replica");
131 fprintf(stderr, "\tCAS: 0x0%llx\n", ni->cas);
132 fprintf(stderr, "\tStatus (RAW): 0x%02x\n", ni->status);
133 fprintf(stderr, "\tExists [CACHE]: %s\n", ni->status & LCB_OBSERVE_NOT_FOUND ? "No" : "Yes");
134 fprintf(stderr, "\tExists [DISK]: %s\n", ni->status & LCB_OBSERVE_PERSISTED ? "Yes" : "No");
135 fprintf(stderr, "\n");
136 }
137
138 /* The next example shows how to use lcb_observe() to only request the
139 * CAS from the master node */
140 obs_info.nresp = 0;
141 memset(obs_info.nodeinfo, 0, sizeof(obs_info.nodeinfo[0]) * nservers);
142
143 fprintf(stderr, "Will request CAS from master...\n");
144 cmd.cmdflags |= LCB_CMDOBSERVE_F_MASTER_ONLY;
145 mctx = lcb_observe3_ctxnew(instance);
146 mctx->addcmd(mctx, (const lcb_CMDBASE*)&cmd);
147 if ((err = mctx->done(mctx, &obs_info)) != LCB_SUCCESS) {
148 fail2("Couldn't schedule observe request!\n", err);
149 }
150
151 lcb_wait(instance);
152
153 assert(obs_info.nresp == 1 && obs_info.nodeinfo[0].master);
154 fprintf(stderr, "CAS on master is 0x%llx\n", obs_info.nodeinfo[0].cas);
155
156 lcb_destroy(instance);
157 free(obs_info.nodeinfo);
158 return EXIT_SUCCESS;
159 }
160