diff --git a/engines/default/default_engine.c b/engines/default/default_engine.c index 13459ef43..3ddfdee55 100644 --- a/engines/default/default_engine.c +++ b/engines/default/default_engine.c @@ -500,7 +500,8 @@ default_set_elem_release(ENGINE_HANDLE* handle, const void *cookie, static ENGINE_ERROR_CODE default_set_elem_insert(ENGINE_HANDLE* handle, const void* cookie, const void* key, const int nkey, eitem *eitem, - item_attr *attrp, bool *created, uint16_t vbucket) + item_attr *attrp, bool *created, uint16_t vbucket, + bool force) { struct default_engine *engine = get_handle(handle); ENGINE_ERROR_CODE ret; @@ -508,7 +509,7 @@ default_set_elem_insert(ENGINE_HANDLE* handle, const void* cookie, ACTION_BEFORE_WRITE(cookie, key, nkey); ret = set_elem_insert(engine, key, nkey, (set_elem_item*)eitem, - attrp, created, cookie); + attrp, created, cookie, force); ACTION_AFTER_WRITE(cookie, ret); return ret; } diff --git a/engines/default/items.c b/engines/default/items.c index c51b654cf..c4702cc95 100644 --- a/engines/default/items.c +++ b/engines/default/items.c @@ -2234,7 +2234,7 @@ static ENGINE_ERROR_CODE do_set_elem_get(struct default_engine *engine, static ENGINE_ERROR_CODE do_set_elem_insert(struct default_engine *engine, hash_item *it, set_elem_item *elem, - const void *cookie) + const void *cookie, bool force) { set_meta_info *info = (set_meta_info *)item_get_meta(it); int32_t real_mcnt = (info->mcnt == -1 ? max_set_size : info->mcnt); @@ -2251,7 +2251,10 @@ static ENGINE_ERROR_CODE do_set_elem_insert(struct default_engine *engine, /* overflow check */ assert(info->ovflact == OVFL_ERROR); if (info->ccnt >= real_mcnt) { - return ENGINE_EOVERFLOW; + if (!force || info->ccnt >= max_set_size) { + return ENGINE_EOVERFLOW; + } + info->mcnt = info->ccnt+1; } /* create the root hash node if it does not exist */ @@ -6675,7 +6678,8 @@ void set_elem_release(struct default_engine *engine, set_elem_item **elem_array, } ENGINE_ERROR_CODE set_elem_insert(struct default_engine *engine, const char *key, const size_t nkey, - set_elem_item *elem, item_attr *attrp, bool *created, const void *cookie) + set_elem_item *elem, item_attr *attrp, bool *created, const void *cookie, + bool force) { hash_item *it = NULL; ENGINE_ERROR_CODE ret; @@ -6698,7 +6702,7 @@ ENGINE_ERROR_CODE set_elem_insert(struct default_engine *engine, const char *key } } if (ret == ENGINE_SUCCESS) { - ret = do_set_elem_insert(engine, it, elem, cookie); + ret = do_set_elem_insert(engine, it, elem, cookie, force); if (ret != ENGINE_SUCCESS && *created) { do_item_unlink(engine, it, ITEM_UNLINK_NORMAL); } diff --git a/engines/default/items.h b/engines/default/items.h index 000316feb..4a48beb1b 100644 --- a/engines/default/items.h +++ b/engines/default/items.h @@ -444,7 +444,8 @@ ENGINE_ERROR_CODE set_elem_insert(struct default_engine *engine, const char *key, const size_t nkey, set_elem_item *elem, item_attr *attrp, - bool *created, const void *cookie); + bool *created, const void *cookie, + bool force); ENGINE_ERROR_CODE set_elem_delete(struct default_engine *engine, const char *key, const size_t nkey, diff --git a/engines/demo/demo_engine.c b/engines/demo/demo_engine.c index 14746d92f..f71fd6988 100644 --- a/engines/demo/demo_engine.c +++ b/engines/demo/demo_engine.c @@ -356,7 +356,8 @@ Demo_set_elem_release(ENGINE_HANDLE* handle, const void *cookie, static ENGINE_ERROR_CODE Demo_set_elem_insert(ENGINE_HANDLE* handle, const void* cookie, const void* key, const int nkey, eitem *eitem, - item_attr *attrp, bool *created, uint16_t vbucket) + item_attr *attrp, bool *created, uint16_t vbucket, + bool force) { return ENGINE_ENOTSUP; } diff --git a/include/memcached/engine.h b/include/memcached/engine.h index 823ca3c0f..0a35f23c5 100644 --- a/include/memcached/engine.h +++ b/include/memcached/engine.h @@ -392,7 +392,7 @@ extern "C" { ENGINE_ERROR_CODE (*set_elem_insert)(ENGINE_HANDLE* handle, const void* cookie, const void* key, const int nkey, eitem *eitem, item_attr *attrp, bool *created, - uint16_t vbucket); + uint16_t vbucket, bool force); ENGINE_ERROR_CODE (*set_elem_delete)(ENGINE_HANDLE* handle, const void* cookie, const void* key, const int nkey, diff --git a/memcached.c b/memcached.c index 22b72262e..fa5adae43 100644 --- a/memcached.c +++ b/memcached.c @@ -1682,7 +1682,7 @@ static void process_sop_insert_complete(conn *c) { ret = mc_engine.v1->set_elem_insert(mc_engine.v0, c, c->coll_key, c->coll_nkey, elem, - c->coll_attrp, &created, 0); + c->coll_attrp, &created, 0, c->force); if (ret == ENGINE_EWOULDBLOCK) { c->ewouldblock = true; ret = ENGINE_SUCCESS; @@ -5072,7 +5072,7 @@ static void process_bin_sop_insert_complete(conn *c) { ret = mc_engine.v1->set_elem_insert(mc_engine.v0, c, c->coll_key, c->coll_nkey, elem, c->coll_attrp, &created, - c->binary_header.request.vbucket); + c->binary_header.request.vbucket, c->force); if (ret == ENGINE_EWOULDBLOCK) { c->ewouldblock = true; ret = ENGINE_SUCCESS; @@ -10586,8 +10586,10 @@ static void process_sop_command(conn *c, token_t *tokens, const size_t ntokens) } vlen += 2; + c->force = (strcmp(tokens[ntokens - 2 - (c->noreply ? 1 : 0)].value, "force") == 0); + int read_ntokens = SOP_KEY_TOKEN + 2; - int post_ntokens = 1 + (c->noreply ? 1 : 0); + int post_ntokens = 1 + (c->noreply ? 1 : 0) + (c->force ? 1: 0); int rest_ntokens = ntokens - read_ntokens - post_ntokens; if (rest_ntokens >= 2) { diff --git a/memcached.h b/memcached.h index 0eddcf4a4..95717e0b2 100644 --- a/memcached.h +++ b/memcached.h @@ -602,6 +602,7 @@ struct conn { char client_ip[16]; bool noreply; /* True if the reply should not be sent. */ + bool force; /* current stats command */ struct { diff --git a/t/coll_sop_forced_insert.t b/t/coll_sop_forced_insert.t new file mode 100644 index 000000000..87957c681 --- /dev/null +++ b/t/coll_sop_forced_insert.t @@ -0,0 +1,60 @@ +#!/usr/bin/perl + +use strict; +use Test::More tests => 51001; +use FindBin qw($Bin); +use lib "$Bin/lib"; +use MemcachedTest; + +my $engine = shift; +my $server = get_memcached($engine); +my $sock = $server->sock; + +my $flags = 13; +my $default_set_size = 4000; +my $maximum_set_size = 50000; +my $cnt; + +sub sop_forced_insert_over_maxcount { + my ($key, $create) = @_; + my $index; + + for ($index = 0; $index < $maximum_set_size; $index++) { + my $val = "datum$index"; + my $vleng = length($val); + my $cmd; + my $rst; + + if ($index == 0) { + $cmd = "sop insert $key $vleng $create force"; + $rst = "CREATED_STORED"; + } + + else { + $cmd = "sop insert $key $vleng force"; + $rst = "STORED"; + } + mem_cmd_is($sock, $cmd, $val, $rst); + } +} + + +sub sop_forced_insert_over_hardlimit{ + my ($key, $from, $to) = @_; + my $index; + + for($index = $from; $index <= $to; $index++){ + my $val = "datum$index"; + my $vleng = length($val); + my $cmd = "sop insert $key $vleng force"; + my $rst = "OVERFLOWED"; + + mem_cmd_is($sock, $cmd, $val, $rst); + } +} + +sop_forced_insert_over_maxcount("skey", "create $flags 0 1"); +sop_forced_insert_over_hardlimit("skey", $maximum_set_size, $maximum_set_size+1000); + +# after test +release_memcached($engine, $server); diff --git a/t/tlist/engine_default_s.txt b/t/tlist/engine_default_s.txt index ee7be63f8..2acbc6aa4 100644 --- a/t/tlist/engine_default_s.txt +++ b/t/tlist/engine_default_s.txt @@ -39,6 +39,7 @@ ./t/coll_pipeline_sop_exist.t ./t/coll_readable_attr.t ./t/coll_sop_segfault_p012611.t +./t/coll_sop_forced_insert.t ./t/coll_sop_unittest.t ./t/daemonize.t ./t/dash-M.t