static void reproduce_double_free_error(void) { libcouchbase_error_t err; struct rvbuf rv; const char *key = "test_compare_and_swap_async_", *val = "{\"bar\" => 1}"; libcouchbase_size_t nkey = strlen(key), nval = strlen(val); /* prefill the bucket */ (void)libcouchbase_set_storage_callback(session, store_callback1); err = libcouchbase_store(session, &rv, LIBCOUCHBASE_SET, key, nkey, val, nval, 0, 0, 0); assert(err == LIBCOUCHBASE_SUCCESS); io->run_event_loop(io); assert(rv.error == LIBCOUCHBASE_SUCCESS); /* run exercise * * 1. get the value and its cas * 2. atomic set new value using old cas */ (void)libcouchbase_set_storage_callback(session, store_callback2); (void)libcouchbase_set_get_callback(session, get_callback); err = libcouchbase_mget(session, &rv, 1, (const void * const *)&key, &nkey, NULL); assert(err == LIBCOUCHBASE_SUCCESS); rv.cas1 = rv.cas2 = 0; io->run_event_loop(io); assert(rv.error == LIBCOUCHBASE_SUCCESS); assert(rv.cas1 > 0); assert(rv.cas2 > 0); assert(rv.cas1 != rv.cas2); }
static void get_callback(libcouchbase_t instance, const void *cookie, libcouchbase_error_t error, const void *key, libcouchbase_size_t nkey, const void *bytes, libcouchbase_size_t nbytes, libcouchbase_uint32_t flags, libcouchbase_cas_t cas) { struct rvbuf *rv = (struct rvbuf *)cookie; const char *val = "{\"bar\"=>1, \"baz\"=>2}"; libcouchbase_size_t nval = strlen(val); libcouchbase_error_t err; rv->error = error; rv->cas1 = cas; err = libcouchbase_store(session, rv, LIBCOUCHBASE_SET, key, nkey, val, nval, 0, 0, cas); assert(err == LIBCOUCHBASE_SUCCESS); (void)instance; (void)bytes; (void)nbytes; (void)flags; }
/** * \brief push tile data to couchbase * * writes the content of mapcache_tile::data to the configured couchbased instance(s) * \private \memberof mapcache_cache_couchbase * \sa mapcache_cache::tile_set() */ static void _mapcache_cache_couchbase_set(mapcache_context *ctx, mapcache_tile *tile) { char *key; libcouchbase_t *instance; libcouchbase_error_t error; const int max_retries = 3; int retries = max_retries; apr_interval_time_t delay; /* set expiration to one day if not configured */ libcouchbase_time_t expires = 86400; if(tile->tileset->auto_expire) expires = tile->tileset->auto_expire; mapcache_cache_couchbase *cache = (mapcache_cache_couchbase*)tile->tileset->cache; key = mapcache_util_get_tile_key(ctx, tile, NULL, " \r\n\t\f\e\a\b", "#"); GC_CHECK_ERROR(ctx); if(!tile->encoded_data) { tile->encoded_data = tile->tileset->format->write(ctx, tile->raw_image, tile->tileset->format); GC_CHECK_ERROR(ctx); } instance = _couchbase_get_connection(ctx, tile); GC_CHECK_ERROR(ctx); do { error = libcouchbase_store(*instance, &error, LIBCOUCHBASE_SET, key, strlen(key), tile->encoded_data->buf, tile->encoded_data->size, 0, expires, 0); if (error != LIBCOUCHBASE_SUCCESS) { _couchbase_release_connection(tile, instance); ctx->set_error(ctx, 500, "failed to store tile %d %d %d to couchbase cache %s due to eror %s.", tile->x, tile->y, tile->z, cache->cache.name, libcouchbase_strerror(*instance, error)); return; } libcouchbase_wait(*instance); if (error == LIBCOUCHBASE_ETMPFAIL) { if (retries > 0) { delay = 100000 * (1 << (max_retries - retries)); // Do an exponential back off of starting at 100 milliseconds apr_sleep(delay); } else { _couchbase_release_connection(tile, instance); ctx->set_error(ctx, 500, "failed to store tile %d %d %d to couchbase cache %s due to %s. Maximum number of retries used.", tile->x, tile->y, tile->z, cache->cache.name, libcouchbase_strerror(*instance, error)); return; } --retries; } else if (error != LIBCOUCHBASE_SUCCESS) { _couchbase_release_connection(tile, instance); ctx->set_error(ctx, 500, "failed to store tile %d %d %d to couchbase cache %s due to error %s.", tile->x, tile->y, tile->z, cache->cache.name, libcouchbase_strerror(*instance, error)); return; } } while (error == LIBCOUCHBASE_ETMPFAIL); _couchbase_release_connection(tile, instance); }