gauc 0.3.0

Couchbase Rust Adapter / CLI
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2010-2014 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "internal.h"
#include <lcbio/iotable.h>

#if defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif

typedef enum {
    LCB_TIMER_STANDALONE = 1 << 0,
    LCB_TIMER_PERIODIC = 1 << 1,
    LCB_TIMER_EX = 1 << 2
} lcb_timer_options;

typedef enum {
    LCB_TIMER_S_ENTERED = 0x01,
    LCB_TIMER_S_DESTROYED = 0x02,
    LCB_TIMER_S_ARMED = 0x04
} lcb_timer_state;

struct lcb_timer_st {
    lcb_uint32_t usec_;
    lcb_timer_state state;
    lcb_timer_options options;
    void *event;
    const void *cookie;
    lcb_timer_callback callback;
    lcb_t instance;
    struct lcbio_TABLE *io;
};

static void timer_rearm(lcb_timer_t timer, lcb_uint32_t usec);
static void timer_disarm(lcb_timer_t timer);
#define lcb_timer_armed(timer) ((timer)->state & LCB_TIMER_S_ARMED)
#define lcb_async_signal(async) lcb_timer_rearm(async, 0)
#define lcb_async_cancel(async) lcb_timer_disarm(async)
#define TMR_IS_PERIODIC(timer) ((timer)->options & LCB_TIMER_PERIODIC)
#define TMR_IS_DESTROYED(timer) ((timer)->state & LCB_TIMER_S_DESTROYED)
#define TMR_IS_STANDALONE(timer) ((timer)->options & LCB_TIMER_STANDALONE)
#define TMR_IS_ARMED(timer) ((timer)->state & LCB_TIMER_S_ARMED)

static void destroy_timer(lcb_timer_t timer) {
    if (timer->event) {
        timer->io->timer.destroy(timer->io->p, timer->event);
    }
    lcbio_table_unref(timer->io);
    memset(timer, 0xff, sizeof(*timer));
    free(timer);
}

static void timer_callback(lcb_socket_t sock, short which, void *arg) {
    lcb_timer_t timer = arg;
    lcb_t instance = timer->instance;

    lcb_assert(TMR_IS_ARMED(timer));
    lcb_assert(!TMR_IS_DESTROYED(timer));

    timer->state |= LCB_TIMER_S_ENTERED;
    timer_disarm(timer);
    timer->callback(timer, instance, timer->cookie);

    if (TMR_IS_DESTROYED(timer) == 0 && TMR_IS_PERIODIC(timer) != 0) {
        timer_rearm(timer, timer->usec_);
        return;
    }
    if (! TMR_IS_STANDALONE(timer)) {
        lcb_aspend_del(&instance->pendops, LCB_PENDTYPE_TIMER, timer);
        lcb_maybe_breakout(instance);
    }
    if (TMR_IS_DESTROYED(timer)) {
        destroy_timer(timer);
    } else {
        timer->state &= ~LCB_TIMER_S_ENTERED;
    }
    (void)sock;(void)which;
}

LIBCOUCHBASE_API
lcb_timer_t lcb_timer_create(lcb_t instance, const void *command_cookie, lcb_uint32_t usec, int periodic, lcb_timer_callback callback, lcb_error_t *error) {
    lcb_timer_options options = 0;
    lcb_timer_t tmr = calloc(1, sizeof(struct lcb_timer_st));
    tmr->io = instance->iotable;

    if (periodic) {
        options |= LCB_TIMER_PERIODIC;
    }
    if (!tmr) {
        *error = LCB_CLIENT_ENOMEM;
        return NULL;
    }
    if (!callback) {
        *error = LCB_EINVAL;
        return NULL;
    }
    if (! (options & LCB_TIMER_STANDALONE)) {
        lcb_assert(instance);
    }

    lcbio_table_ref(tmr->io);
    tmr->instance = instance;
    tmr->callback = callback;
    tmr->cookie = command_cookie;
    tmr->options = options;
    tmr->event = tmr->io->timer.create(tmr->io->p);

    if (tmr->event == NULL) {
        free(tmr);
        *error = LCB_CLIENT_ENOMEM;
        return NULL;
    }

    if ( (options & LCB_TIMER_STANDALONE) == 0) {
        lcb_aspend_add(&instance->pendops, LCB_PENDTYPE_TIMER, tmr);
    }

    timer_rearm(tmr, usec);

    *error = LCB_SUCCESS;
    return tmr;
}

LIBCOUCHBASE_API
lcb_error_t lcb_timer_destroy(lcb_t instance, lcb_timer_t timer) {
    int standalone = timer->options & LCB_TIMER_STANDALONE;
    if (!standalone) {
        lcb_aspend_del(&instance->pendops, LCB_PENDTYPE_TIMER, timer);
    }
    timer_disarm(timer);
    if (timer->state & LCB_TIMER_S_ENTERED) {
        timer->state |= LCB_TIMER_S_DESTROYED;
        lcb_assert(TMR_IS_DESTROYED(timer));
    } else {
        destroy_timer(timer);
    }
    return LCB_SUCCESS;
}
static void timer_disarm(lcb_timer_t timer) {
    if (!TMR_IS_ARMED(timer)) {
        return;
    }
    timer->state &= ~LCB_TIMER_S_ARMED;
    timer->io->timer.cancel(timer->io->p, timer->event);
}
static void timer_rearm(lcb_timer_t timer, lcb_uint32_t usec) {
    if (TMR_IS_ARMED(timer)) {
        timer_disarm(timer);
    }
    timer->usec_ = usec;
    timer->io->timer.schedule(timer->io->p, timer->event, usec, timer, timer_callback);
    timer->state |= LCB_TIMER_S_ARMED;
}

LCB_INTERNAL_API void lcb__timer_destroy_nowarn(lcb_t instance, lcb_timer_t timer) {
    lcb_timer_destroy(instance, timer);
}

struct user_cookie {
    void *cookie;
    struct lcb_callback_st callbacks;
    lcb_error_t retcode;
};

static void restore_user_env(lcb_t instance);
static void restore_wrapping_env(lcb_t instance, struct user_cookie *user, lcb_error_t error);
static void bootstrap_callback(lcb_t instance, lcb_error_t err) {
    struct user_cookie *c = (void *)instance->cookie;
    c->retcode = err;
}
static void stat_callback(lcb_t instance, const void *command_cookie, lcb_error_t error, const lcb_server_stat_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.stat(instance, command_cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void version_callback(lcb_t instance, const void *command_cookie, lcb_error_t error, const lcb_server_version_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.version(instance, command_cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void verbosity_callback(lcb_t instance, const void *command_cookie, lcb_error_t error, const lcb_verbosity_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.verbosity(instance, command_cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void get_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_get_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.get(instance, cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void store_callback(lcb_t instance, const void *cookie, lcb_storage_t operation, lcb_error_t error, const lcb_store_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.store(instance, cookie, operation, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void arithmetic_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_arithmetic_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.arithmetic(instance, cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void remove_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_remove_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.remove(instance, cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void touch_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_touch_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.touch(instance, cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void http_complete_callback(lcb_http_request_t request, lcb_t instance, const void *cookie, lcb_error_t error, const lcb_http_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.http_complete(request, instance, cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void http_data_callback(lcb_http_request_t request, lcb_t instance, const void *cookie, lcb_error_t error, const lcb_http_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.http_data(request, instance, cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void flush_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_flush_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.flush(instance, cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void observe_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_observe_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.observe(instance, cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void durability_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_durability_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.durability(instance, cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void unlock_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_unlock_resp_t *resp) {
    struct user_cookie *c = (void *)instance->cookie;
    restore_user_env(instance);
    c->callbacks.unlock(instance, cookie, error, resp);
    restore_wrapping_env(instance, c, error);
}
static void restore_user_env(lcb_t instance) {
    struct user_cookie *cookie = (void *)instance->cookie;
    /* Restore the users environment */
    instance->cookie = cookie->cookie;
    instance->callbacks = cookie->callbacks;
}

static void
restore_wrapping_env(lcb_t instance, struct user_cookie *user, lcb_error_t error) {
    user->callbacks = instance->callbacks;
    /* Install new callbacks */
    instance->callbacks.get = get_callback;
    instance->callbacks.store = store_callback;
    instance->callbacks.arithmetic = arithmetic_callback;
    instance->callbacks.remove = remove_callback;
    instance->callbacks.stat = stat_callback;
    instance->callbacks.version = version_callback;
    instance->callbacks.verbosity = verbosity_callback;
    instance->callbacks.touch = touch_callback;
    instance->callbacks.flush = flush_callback;
    instance->callbacks.bootstrap = bootstrap_callback;
    instance->callbacks.http_complete = http_complete_callback;
    instance->callbacks.http_data = http_data_callback;
    instance->callbacks.observe = observe_callback;
    instance->callbacks.unlock = unlock_callback;
    instance->callbacks.durability = durability_callback;

    user->cookie = (void *)instance->cookie;
    user->retcode = error;
    instance->cookie = user;
}

lcb_error_t
lcb__synchandler_return(lcb_t instance)
{
    struct user_cookie cookie;
    restore_wrapping_env(instance, &cookie, LCB_SUCCESS);
    lcb_wait(instance);
    restore_user_env(instance);
    return cookie.retcode;
}

LIBCOUCHBASE_API
void
lcb_behavior_set_syncmode(lcb_t instance, lcb_syncmode_t mode)
{
    LCBT_SETTING(instance, syncmode) = mode;
}
LIBCOUCHBASE_API
lcb_syncmode_t
lcb_behavior_get_syncmode(lcb_t instance)
{
    return LCBT_SETTING(instance, syncmode);
}

LIBCOUCHBASE_API
lcb_error_t lcb_get_last_error(lcb_t instance){return instance->last_error;}

LIBCOUCHBASE_API
lcb_error_t lcb__create_compat_230(lcb_cluster_t type, const void *specific, lcb_t *instance, struct lcb_io_opt_st *io)
{
    struct lcb_create_st cst = { 0 };
    const struct lcb_cached_config_st *cfg = specific;
    const struct lcb_create_st *crp = &cfg->createopt;
    lcb_error_t err;
    lcb_size_t to_copy = 0;

    if (type != LCB_CACHED_CONFIG) {
        return LCB_NOT_SUPPORTED;
    }

    if (crp->version == 0) {
        to_copy = sizeof(cst.v.v0);
    } else if (crp->version == 1) {
        to_copy = sizeof(cst.v.v1);
    } else if (crp->version >= 2) {
        to_copy = sizeof(cst.v.v2);
    } else {
        /* using version 3? */
        return LCB_NOT_SUPPORTED;
    }
    memcpy(&cst, crp, to_copy);

    if (io) {
        cst.v.v0.io = io;
    }
    err = lcb_create(instance, &cst);
    if (err != LCB_SUCCESS) {
        return err;
    }
    err = lcb_cntl(*instance, LCB_CNTL_SET, LCB_CNTL_CONFIGCACHE,
                   (void *)cfg->cachefile);
    if (err != LCB_SUCCESS) {
        lcb_destroy(*instance);
    }
    return err;
}
struct compat_220 {
    struct {
        int version;
        struct lcb_create_st1 v1;
    } createopt;
    const char *cachefile;
};

struct compat_230 {
    struct {
        int version;
        struct lcb_create_st2 v2;
    } createopt;
    const char *cachefile;
};

#undef lcb_create_compat
/**
 * This is _only_ called for versions <= 2.3.0.
 * >= 2.3.0 uses the _230() symbol.
 *
 * The big difference between this and the _230 function is the struct layout,
 * where the newer one contains the filename _before_ the creation options.
 *
 * Woe to he who relies on the compat_st as a 'subclass' of create_st..
 */

LIBCOUCHBASE_API
lcb_error_t lcb_create_compat(lcb_cluster_t type, const void *specific, lcb_t *instance, struct lcb_io_opt_st *io);
LIBCOUCHBASE_API
lcb_error_t lcb_create_compat(lcb_cluster_t type, const void *specific, lcb_t *instance, struct lcb_io_opt_st *io)
{
    struct lcb_cached_config_st dst;
    const struct compat_220* src220 = specific;

    if (type == LCB_MEMCACHED_CLUSTER) {
        return lcb__create_compat_230(type, specific, instance, io);
    } else if (type != LCB_CACHED_CONFIG) {
        return LCB_NOT_SUPPORTED;
    }
#define copy_compat(v) \
    memcpy(&dst.createopt, &v->createopt, sizeof(v->createopt)); \
    dst.cachefile = v->cachefile;

    if (src220->createopt.version >= 2 || src220->cachefile == NULL) {
        const struct compat_230* src230 = specific;
        copy_compat(src230);
    } else {
        copy_compat(src220);
    }
    return lcb__create_compat_230(type, &dst, instance, io);
}
LIBCOUCHBASE_API void lcb_flush_buffers(lcb_t instance, const void *cookie) {
    (void)instance;(void)cookie;
}

LIBCOUCHBASE_API
lcb_error_t lcb_verify_struct_size(lcb_U32 id, lcb_U32 version, lcb_SIZE size)
{
    #define X(sname, sabbrev, idval, vernum) \
    if (idval == id && size == sizeof(sname) && version <= vernum) { return LCB_SUCCESS; }
    LCB_XSSIZES(X);
    #undef X
    return LCB_EINVAL;
}