} else {
ret = engine->getEpStore()->setWithMeta(*mutation->getItem(), 0, NULL,
consumer->getCookie(), true,
- true, INITIAL_NRU_VALUE, false,
+ true, INITIAL_NRU_VALUE,
+ GenerateBySeqno::No,
+ GenerateCas::No,
mutation->getExtMetaData(),
true);
}
&delCas, NULL, deletion->getVBucket(),
consumer->getCookie(), true,
&meta, vb->isBackfillPhase(),
- false, deletion->getBySeqno(),
+ GenerateBySeqno::No,
+ GenerateCas::No,
+ deletion->getBySeqno(),
deletion->getExtMetaData(),
true);
if (ret == ENGINE_KEY_ENOENT) {
bool force,
bool allowExisting,
uint8_t nru,
- bool genBySeqno,
+ GenerateBySeqno genBySeqno,
+ GenerateCas genCas,
ExtendedMetaData *emd,
bool isReplication)
{
case WAS_DIRTY:
case WAS_CLEAN:
vb->setMaxCasAndTrackDrift(v->getCas());
- queueDirty(vb, v, &lh, seqno,
- genBySeqno ? GenerateBySeqno::Yes : GenerateBySeqno::No,
- GenerateCas::No);
+ queueDirty(vb, v, &lh, seqno, genBySeqno, genCas);
break;
case NOT_FOUND:
ret = ENGINE_KEY_ENOENT;
bool force,
ItemMetaData *itemMeta,
bool tapBackfill,
- bool genBySeqno,
+ GenerateBySeqno genBySeqno,
+ GenerateCas generateCas,
uint64_t bySeqno,
ExtendedMetaData *emd,
bool isReplication)
break;
case WAS_DIRTY:
case WAS_CLEAN:
- if (!genBySeqno) {
+ if (genBySeqno == GenerateBySeqno::No) {
v->setBySeqno(bySeqno);
}
vb->setMaxCasAndTrackDrift(v->getCas());
if (tapBackfill) {
- tapQueueDirty(*vb, v, lh, seqno,
- genBySeqno ? GenerateBySeqno::Yes : GenerateBySeqno::No);
+ tapQueueDirty(*vb, v, lh, seqno, genBySeqno);
} else {
- queueDirty(vb, v, &lh, seqno,
- genBySeqno ? GenerateBySeqno::Yes : GenerateBySeqno::No,
- GenerateCas::No);
+ queueDirty(vb, v, &lh, seqno, genBySeqno, generateCas);
}
break;
case NEED_BG_FETCH:
bool force,
bool allowExisting,
uint8_t nru = 0xff,
- bool genBySeqno = true,
+ GenerateBySeqno genBySeqno = GenerateBySeqno::Yes,
+ GenerateCas genCas = GenerateCas::No,
ExtendedMetaData *emd = NULL,
bool isReplication = false);
const void *cookie,
bool force,
ItemMetaData *itemMeta,
- bool tapBackfill=false,
- bool genBySeqno=true,
- uint64_t bySeqno=0,
- ExtendedMetaData *emd = NULL,
- bool isReplication=false);
+ bool tapBackfill,
+ GenerateBySeqno genBySeqno,
+ GenerateCas generateCas,
+ uint64_t bySeqno,
+ ExtendedMetaData *emd,
+ bool isReplication);
void reset();
return rv;
}
+protocol_binary_response_status EventuallyPersistentEngine::decodeWithMetaOptions(
+ protocol_binary_request_delete_with_meta* request,
+ GenerateCas& generateCas,
+ bool& skipConflictResolution,
+ int& keyOffset) {
+ uint8_t extlen = request->message.header.request.extlen;
+ keyOffset = 0;
+ bool forceFlag = false;
+ if (extlen == 28 || extlen == 30) {
+ uint32_t options;
+ memcpy(&options, request->bytes + sizeof(request->bytes),
+ sizeof(options));
+ options = ntohl(options);
+ keyOffset = 4; // 4 bytes for options
+
+ if (options & SKIP_CONFLICT_RESOLUTION_FLAG) {
+ skipConflictResolution = true;
+ }
+
+ if (options & FORCE_ACCEPT_WITH_META_OPS) {
+ forceFlag = true;
+ }
+
+ if (options & REGENERATE_CAS) {
+ generateCas = GenerateCas::Yes;
+ }
+ }
+
+ // Validate options
+ // If regenerate CAS then skip conflict resolution must be set
+ // If LWW force must be set
+ // If !LWW then force cannot be set).
+ if ((generateCas == GenerateCas::Yes && !skipConflictResolution) ||
+ (configuration.getConflictResolutionType() == "lww" && !forceFlag &&
+ generateCas == GenerateCas::No) ||
+ (forceFlag && (configuration.getConflictResolutionType() != "lww"))) {
+ return PROTOCOL_BINARY_RESPONSE_EINVAL;
+ }
+
+
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
ENGINE_ERROR_CODE EventuallyPersistentEngine::setWithMeta(const void* cookie,
protocol_binary_request_set_with_meta *request,
ADD_RESPONSE response)
// revid_nbytes, flags and exptime is mandatory fields.. and we need a key
uint8_t extlen = request->message.header.request.extlen;
uint16_t keylen = ntohs(request->message.header.request.keylen);
- if ((extlen != 24 // Packet without nmeta or options
- && extlen != 28 // Packet with options but without nmeta
- && extlen != 26) // Packet with nmeta
+ // extlen, the size dicates what is encoded.
+ // 24 = no nmeta and no options
+ // 26 = nmeta
+ // 28 = options (4-byte field)
+ // 30 = options and nmeta (options followed by nmeta)
+ // so 27, 25 etc... are illegal
+ if ((extlen != 24 && extlen != 26 && extlen != 28 && extlen != 30)
|| keylen == 0) {
return sendResponse(response, NULL, 0, NULL, 0, NULL, 0,
PROTOCOL_BINARY_RAW_BYTES,
uint64_t seqno = ntohll(request->message.body.seqno);
uint64_t cas = ntohll(request->message.body.cas);
- bool force = false;
- ExtendedMetaData *emd = NULL;
+ bool skipConflictResolution = false;
+ GenerateCas generateCas = GenerateCas::No;
+ std::unique_ptr<ExtendedMetaData> emd;
+ int keyOffset = 0;
+ protocol_binary_response_status error = PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ if ((error = decodeWithMetaOptions(request, generateCas,
+ skipConflictResolution, keyOffset)) !=
+ PROTOCOL_BINARY_RESPONSE_SUCCESS) {
+ return sendResponse(response, NULL, 0, NULL, 0, NULL, 0,
+ PROTOCOL_BINARY_RAW_BYTES, error, 0, cookie);
+ }
- if (extlen == 28) {
- uint32_t options;
- memcpy(&options, request->bytes + sizeof(request->bytes),
- sizeof(options));
- key += 4; // 4 bytes for options
- if (ntohl(options) & SKIP_CONFLICT_RESOLUTION_FLAG) {
- force = true;
- }
- } else if (extlen == 26) {
- uint16_t nmeta;
- memcpy(&nmeta, request->bytes + sizeof(request->bytes),
- sizeof(nmeta));
- key += 2; // 2 bytes for nmeta
+ if (extlen == 26 || extlen == 30) {
+ uint16_t nmeta = 0;
+ memcpy(&nmeta, key + keyOffset, sizeof(nmeta));
+ keyOffset += 2; // 2 bytes for nmeta
nmeta = ntohs(nmeta);
if (nmeta > 0) {
// Correct the vallen
vallen -= nmeta;
- emd = new ExtendedMetaData(key + keylen + vallen, nmeta);
-
- if (emd == NULL) {
+ try {
+ emd.reset(new ExtendedMetaData(key + keylen + keyOffset + vallen,
+ nmeta));
+ } catch (const std::bad_alloc&) {
return sendResponse(response, NULL, 0, NULL, 0, NULL, 0,
- PROTOCOL_BINARY_RAW_BYTES,
- PROTOCOL_BINARY_RESPONSE_ENOMEM, 0, cookie);
+ PROTOCOL_BINARY_RAW_BYTES,
+ PROTOCOL_BINARY_RESPONSE_ENOMEM, 0, cookie);
}
if (emd->getStatus() == ENGINE_EINVAL) {
- delete emd;
return sendResponse(response, NULL, 0, NULL, 0, NULL, 0,
- PROTOCOL_BINARY_RAW_BYTES,
- PROTOCOL_BINARY_RESPONSE_EINVAL, 0, cookie);
+ PROTOCOL_BINARY_RAW_BYTES,
+ PROTOCOL_BINARY_RESPONSE_EINVAL, 0, cookie);
}
}
}
PROTOCOL_BINARY_RESPONSE_E2BIG, 0, cookie);
}
- uint8_t *dta = key + keylen;
+ uint8_t* dta = key + keyOffset + keylen;
if (!isDatatypeSupported(cookie)) {
const int len = vallen;
uint8_t ext_meta[1];
uint8_t ext_len = EXT_META_LEN;
*(ext_meta) = datatype;
- Item *itm = new Item(key, keylen, flags, expiration, dta, vallen,
+ Item *itm = new Item(key + keyOffset, keylen, flags, expiration, dta, vallen,
ext_meta, ext_len, cas, -1, vbucket);
if (itm == NULL) {
ENGINE_ERROR_CODE ret = epstore->setWithMeta(*itm, ntohll(request->
message.header.request.cas),
- &by_seqno, cookie, force,
- allowExisting, 0xff, true,
- emd);
-
- delete emd;
+ &by_seqno, cookie,
+ skipConflictResolution,
+ allowExisting, 0xff,
+ GenerateBySeqno::Yes,
+ generateCas,
+ emd.get(), false);
if (ret == ENGINE_SUCCESS) {
++stats.numOpsSetMeta;
// revid_nbytes, flags and exptime is mandatory fields.. and we need a key
uint16_t nkey = ntohs(request->message.header.request.keylen);
uint8_t extlen = request->message.header.request.extlen;
- if ((extlen != 24 // Packet without nmeta or options
- && extlen != 28 // Packet with options but without nmeta
- && extlen != 26) // Packet with nmeta
+ // extlen, the size dicates what is encoded.
+ // 24 = no nmeta and no options
+ // 26 = nmeta
+ // 28 = options (4-byte field)
+ // 30 = options and nmeta (options followed by nmeta)
+ // so 27, 25 etc... are illegal
+ if ((extlen != 24 && extlen != 26 && extlen != 28 && extlen != 30)
|| nkey == 0) {
return sendResponse(response, NULL, 0, NULL, 0, NULL, 0,
PROTOCOL_BINARY_RAW_BYTES,
}
uint8_t opcode = request->message.header.request.opcode;
- const char *key_ptr = reinterpret_cast<const char*>(request->bytes);
- key_ptr += sizeof(request->bytes);
uint16_t vbucket = ntohs(request->message.header.request.vbucket);
uint64_t cas = ntohll(request->message.header.request.cas);
uint64_t seqno = ntohll(request->message.body.seqno);
uint64_t metacas = ntohll(request->message.body.cas);
- bool force = false;
- ExtendedMetaData *emd = NULL;
+ bool skipConflictResolution = false;
+ GenerateCas generateCas = GenerateCas::No;
+ std::unique_ptr<ExtendedMetaData> emd;
+ int keyOffset = 0;
+ protocol_binary_response_status error = PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ if ((error = decodeWithMetaOptions(request, generateCas,
+ skipConflictResolution, keyOffset)) !=
+ PROTOCOL_BINARY_RESPONSE_SUCCESS) {
+ return sendResponse(response, NULL, 0, NULL, 0, NULL, 0,
+ PROTOCOL_BINARY_RAW_BYTES, error, 0, cookie);
+ }
- if (extlen == 28) {
- uint32_t options;
- memcpy(&options, request->bytes + sizeof(request->bytes),
- sizeof(options));
- key_ptr += 4; // 4 bytes for options
- if (ntohl(options) & SKIP_CONFLICT_RESOLUTION_FLAG) {
- force = true;
- }
- } else if (extlen == 26) {
- uint16_t nmeta;
+ if (extlen == 26 || extlen == 30) {
+ uint16_t nmeta = 0;
memcpy(&nmeta, request->bytes + sizeof(request->bytes),
sizeof(nmeta));
- key_ptr += 2; // 2 bytes for nmeta
+ keyOffset += 2; // 2 bytes for nmeta
nmeta = ntohs(nmeta);
if (nmeta > 0) {
- emd = new ExtendedMetaData(key_ptr + nkey, nmeta);
-
- if (emd == NULL ) {
+ try {
+ emd.reset(new ExtendedMetaData(request->bytes +
+ nkey +
+ keyOffset, nmeta));
+ } catch (const std::bad_alloc&) {
return sendResponse(response, NULL, 0, NULL, 0, NULL, 0,
- PROTOCOL_BINARY_RAW_BYTES,
- PROTOCOL_BINARY_RESPONSE_ENOMEM, 0, cookie);
+ PROTOCOL_BINARY_RAW_BYTES,
+ PROTOCOL_BINARY_RESPONSE_ENOMEM, 0, cookie);
}
if (emd->getStatus() == ENGINE_EINVAL) {
- delete emd;
return sendResponse(response, NULL, 0, NULL, 0, NULL, 0,
- PROTOCOL_BINARY_RAW_BYTES,
- PROTOCOL_BINARY_RESPONSE_EINVAL, 0, cookie);
+ PROTOCOL_BINARY_RAW_BYTES,
+ PROTOCOL_BINARY_RESPONSE_EINVAL, 0, cookie);
}
}
}
+ const char *key_ptr = reinterpret_cast<const char*>(request->bytes +
+ keyOffset +
+ sizeof(request->bytes));
std::string key(key_ptr, nkey);
ItemMetaData itm_meta(metacas, seqno, flags, expiration);
uint64_t by_seqno = 0;
uint64_t vb_uuid = 0;
- ENGINE_ERROR_CODE ret = epstore->deleteWithMeta(key, &cas, &by_seqno, vbucket, cookie,
- force, &itm_meta, false, true, 0, emd);
-
- delete emd;
+ ENGINE_ERROR_CODE ret = epstore->deleteWithMeta(key, &cas, &by_seqno,
+ vbucket, cookie,
+ skipConflictResolution,
+ &itm_meta, false,
+ GenerateBySeqno::Yes,
+ generateCas, 0,
+ emd.get(), false);
if (ret == ENGINE_SUCCESS) {
stats.numOpsDelMeta++;
// server.
void initializeEngineCallbacks();
+ /*
+ * Private helper method for decoding the options on set/del_with_meta.
+ * Tighly coupled to the logic of both those functions, it will
+ * take a request pointer and locate and validate any options within.
+ * @param request pointer to the set/del_with_meta request packet
+ * @param generateCas set to Yes if CAS regeneration is enabled.
+ * @param skipConflictResolution set to true if conflict resolution should
+ * not be performed.
+ * @param keyOffset set to the number of bytes which are to be skipped to
+ * locate the key.
+ */
+ protocol_binary_response_status decodeWithMetaOptions(
+ protocol_binary_request_delete_with_meta* request,
+ GenerateCas& generateCas,
+ bool& skipConflictResolution,
+ int& keyOffset);
+
SERVER_HANDLE_V1 *serverApi;
EventuallyPersistentStore *epstore;
WorkLoadPolicy *workload;
ret = epstore->addTAPBackfillItem(*item, nru, true);
}
else {
- ret = epstore->setWithMeta(*item, 0, NULL, this, true, true, nru, true,
+ ret = epstore->setWithMeta(*item, 0, NULL, this, true, true, nru,
+ GenerateBySeqno::Yes,
+ GenerateCas::No,
NULL, true);
}
ItemMetaData itemMeta(cas, revSeqno, 0, 0);
ret = epstore->deleteWithMeta(key_str, &delCas, NULL, vbucket, this, true,
&itemMeta, isBackfillPhase(vbucket),
- true, 0, NULL, true);
+ GenerateBySeqno::Yes, GenerateCas::No, 0,
+ NULL, true);
if (ret == ENGINE_KEY_ENOENT) {
ret = ENGINE_SUCCESS;
return req;
}
-void add_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
- const size_t keylen, const char *val, const size_t vallen,
- const uint32_t vb, ItemMetaData *itemMeta,
- bool skipConflictResolution, uint8_t datatype,
- bool includeExtMeta) {
- int blen = 0;
- char *ext;
- ExtendedMetaData *emd = NULL;
- if (!includeExtMeta) {
- blen = skipConflictResolution ? 28 : 24;
- ext = new char[blen];
- encodeWithMetaExt(ext, itemMeta);
-
- if (skipConflictResolution) {
- uint32_t flag = SKIP_CONFLICT_RESOLUTION_FLAG;
- flag = htonl(flag);
- memcpy(ext + 24, (char*)&flag, sizeof(flag));
- }
- } else {
- blen = 26;
- ext = new char[blen];
- encodeWithMetaExt(ext, itemMeta);
- emd = new ExtendedMetaData();
- // nmeta added to ext below
- }
-
- protocol_binary_request_header *pkt;
- if (emd) {
- std::pair<const char*, uint16_t> meta = emd->getExtMeta();
- uint16_t nmeta = htons(meta.second);
- memcpy(ext + 24, (char*)&nmeta, sizeof(nmeta));
- pkt = createPacket(PROTOCOL_BINARY_CMD_ADD_WITH_META, vb, 0, ext, blen, key,
- keylen, val, vallen, datatype, meta.first, meta.second);
- delete emd;
- } else {
- pkt = createPacket(PROTOCOL_BINARY_CMD_ADD_WITH_META, vb, 0, ext, blen, key,
- keylen, val, vallen, datatype);
- }
- check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
- "Expected to be able to store with meta");
- cb_free(pkt);
- delete[] ext;
-}
-
void changeVBFilter(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, std::string name,
std::map<uint16_t, uint64_t> &filtermap) {
std::stringstream value;
void del_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
const size_t keylen, const uint32_t vb,
ItemMetaData *itemMeta, uint64_t cas_for_delete,
- bool skipConflictResolution, bool includeExtMeta,
- const void *cookie) {
- int blen = 0;
- char *ext;
- ExtendedMetaData *emd = NULL;
- if (!includeExtMeta) {
- blen = skipConflictResolution ? 28 : 24;
- ext = new char[blen];
- encodeWithMetaExt(ext, itemMeta);
-
- if (skipConflictResolution) {
- uint32_t flag = SKIP_CONFLICT_RESOLUTION_FLAG;
- flag = htonl(flag);
- memcpy(ext + 24, (char*)&flag, sizeof(flag));
- }
- } else {
- blen = 26;
- ext = new char[blen];
- encodeWithMetaExt(ext, itemMeta);
- emd = new ExtendedMetaData();
- // nmeta added to ext below
+ uint32_t options, const void *cookie,
+ const std::vector<char>& nmeta) {
+ int blen = 24;
+ std::unique_ptr<char[]> ext(new char[30]);
+ std::unique_ptr<ExtendedMetaData> emd;
+
+ encodeWithMetaExt(ext.get(), itemMeta);
+
+ if (options) {
+ uint32_t optionsSwapped = htonl(options);
+ memcpy(ext.get() + blen, (char*)&optionsSwapped, sizeof(optionsSwapped));
+ blen += sizeof(uint32_t);
}
- protocol_binary_request_header *pkt;
- if (emd) {
- std::pair<const char*, uint16_t> meta = emd->getExtMeta();
- uint16_t nmeta = htons(meta.second);
- memcpy(ext + 24, (char*)&nmeta, sizeof(nmeta));
- pkt = createPacket(PROTOCOL_BINARY_CMD_DEL_WITH_META, vb, cas_for_delete,
- ext, blen, key, keylen, NULL, 0, 0x00, meta.first,
- meta.second);
- delete emd;
- } else {
- pkt = createPacket(PROTOCOL_BINARY_CMD_DEL_WITH_META, vb, cas_for_delete,
- ext, blen, key, keylen, NULL, 0, 0x00);
+ if (nmeta.size() > 0) {
+ uint16_t nmetaSize = htons(nmeta.size());
+ memcpy(ext.get() + blen, (char*)&nmetaSize, sizeof(nmetaSize));
+ blen += sizeof(uint16_t);
}
+
+ protocol_binary_request_header *pkt;
+ pkt = createPacket(PROTOCOL_BINARY_CMD_DEL_WITH_META, vb, cas_for_delete,
+ ext.get(), blen, key, keylen, NULL, 0,
+ PROTOCOL_BINARY_RAW_BYTES, nmeta.data(), nmeta.size());
+
check(h1->unknown_command(h, cookie, pkt, add_response_set_del_meta) == ENGINE_SUCCESS,
"Expected to be able to delete with meta");
cb_free(pkt);
- delete[] ext;
}
void evict_key(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
}
}
-void set_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
- const size_t keylen, const char *val, const size_t vallen,
- const uint32_t vb, ItemMetaData *itemMeta,
- uint64_t cas_for_set, bool skipConflictResolution,
- uint8_t datatype, bool includeExtMeta, const void *cookie) {
- int blen = 0;
- char *ext;
- ExtendedMetaData *emd = NULL;
- if (!includeExtMeta) {
- blen = skipConflictResolution ? 28 : 24;
- ext = new char[blen];
- encodeWithMetaExt(ext, itemMeta);
-
- if (skipConflictResolution) {
- uint32_t flag = SKIP_CONFLICT_RESOLUTION_FLAG;
- flag = htonl(flag);
- memcpy(ext + 24, (char*)&flag, sizeof(flag));
- }
- } else {
- blen = 26;
- ext = new char[blen];
- encodeWithMetaExt(ext, itemMeta);
- emd = new ExtendedMetaData();
- // nmeta added to ext below
+static void store_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
+ protocol_binary_command cmd, const char *key,
+ const size_t keylen, const char *val, const size_t vallen,
+ const uint32_t vb, ItemMetaData *itemMeta,
+ uint64_t cas_for_store, uint32_t options,
+ uint8_t datatype, const void *cookie,
+ const std::vector<char>& nmeta) {
+ int blen = 24;
+ std::unique_ptr<char[]> ext(new char[30]);
+ std::unique_ptr<ExtendedMetaData> emd;
+
+ encodeWithMetaExt(ext.get(), itemMeta);
+
+ if (options) {
+ uint32_t optionsSwapped = htonl(options);
+ memcpy(ext.get() + blen, (char*)&optionsSwapped, sizeof(optionsSwapped));
+ blen += sizeof(uint32_t);
}
- protocol_binary_request_header *pkt;
- if (emd) {
- std::pair<const char*, uint16_t> meta = emd->getExtMeta();
- uint16_t nmeta = htons(meta.second);
- memcpy(ext + 24, (char*)&nmeta, sizeof(nmeta));
- pkt = createPacket(PROTOCOL_BINARY_CMD_SET_WITH_META, vb, cas_for_set, ext,
- blen, key, keylen, val, vallen, datatype, meta.first,
- meta.second);
- delete emd;
- } else {
- pkt = createPacket(PROTOCOL_BINARY_CMD_SET_WITH_META, vb, cas_for_set, ext,
- blen, key, keylen, val, vallen, datatype);
+ if (nmeta.size() > 0) {
+ uint16_t nmetaSize = htons(nmeta.size());
+ memcpy(ext.get() + blen, (char*)&nmetaSize, sizeof(nmetaSize));
+ blen += sizeof(uint16_t);
}
+ protocol_binary_request_header *pkt;
+ pkt = createPacket(cmd, vb, cas_for_store, ext.get(), blen, key, keylen,
+ val, vallen, datatype, nmeta.data(), nmeta.size());
+
check(h1->unknown_command(h, cookie, pkt, add_response_set_del_meta) == ENGINE_SUCCESS,
"Expected to be able to store with meta");
cb_free(pkt);
- delete[] ext;
+}
+
+void set_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
+ const size_t keylen, const char *val, const size_t vallen,
+ const uint32_t vb, ItemMetaData *itemMeta,
+ uint64_t cas_for_set, uint32_t options, uint8_t datatype,
+ const void *cookie, const std::vector<char>& nmeta) {
+ store_with_meta(h, h1, PROTOCOL_BINARY_CMD_SET_WITH_META, key, keylen, val,
+ vallen, vb, itemMeta, cas_for_set, options, datatype,
+ cookie, nmeta);
+}
+
+void add_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
+ const size_t keylen, const char *val, const size_t vallen,
+ const uint32_t vb, ItemMetaData *itemMeta,
+ uint64_t cas_for_add, uint32_t options, uint8_t datatype,
+ const void *cookie, const std::vector<char>& nmeta) {
+ store_with_meta(h, h1, PROTOCOL_BINARY_CMD_ADD_WITH_META, key, keylen, val,
+ vallen, vb, itemMeta, cas_for_add, options, datatype,
+ cookie, nmeta);
}
void return_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
// XDCR Operations
void set_drift_counter_state(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
int64_t initialDrift);
-void add_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
- const size_t keylen, const char *val, const size_t vallen,
- const uint32_t vb, ItemMetaData *itemMeta,
- bool skipConflictResolution = false,
- uint8_t datatype = 0x00, bool includeExtMeta = false);
+
bool get_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char* key,
bool reqExtMeta = false, const void* cookie = nullptr);
-void del_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
- const size_t keylen, const uint32_t vb,
- ItemMetaData *itemMeta, uint64_t cas_for_delete = 0,
- bool skipConflictResolution = false,
- bool includeExtMeta = false, const void *cookie = NULL);
+
void set_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
const size_t keylen, const char *val, const size_t vallen,
const uint32_t vb, ItemMetaData *itemMeta,
- uint64_t cas_for_set, bool skipConflictResolution = false,
- uint8_t datatype = 0x00, bool includeExtMeta = false,
- const void *cookie = NULL);
+ uint64_t cas_for_set, uint32_t options = 0,
+ uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES,
+ const void* cookie = nullptr,
+ const std::vector<char>& nmeta = {});
+
+void add_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
+ const size_t keylen, const char *val, const size_t vallen,
+ const uint32_t vb, ItemMetaData *itemMeta,
+ uint64_t cas_for_add = 0, uint32_t options = 0,
+ uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES,
+ const void* cookie = nullptr,
+ const std::vector<char>& nmeta = {});
+
+void del_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
+ const size_t keylen, const uint32_t vb,
+ ItemMetaData* itemMeta, uint64_t cas_for_delete = 0,
+ uint32_t options = 0, const void *cookie = nullptr,
+ const std::vector<char>& nmeta = {});
+
void return_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
const size_t keylen, const char *val, const size_t vallen,
const uint32_t vb, const uint64_t cas, const uint32_t flags,
const uint32_t exp, const uint32_t type,
- uint8_t datatype = 0x00, const void *cookie = NULL);
+ uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES,
+ const void *cookie = nullptr);
+
void set_ret_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
const size_t keylen, const char *val, const size_t vallen,
const uint32_t vb, const uint64_t cas = 0,
const uint32_t flags = 0, const uint32_t exp = 0,
- uint8_t datatype = 0x00, const void *cookie = NULL);
+ uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES,
+ const void *cookie = nullptr);
+
void add_ret_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
const size_t keylen, const char *val, const size_t vallen,
const uint32_t vb, const uint64_t cas = 0,
const uint32_t flags = 0, const uint32_t exp = 0,
- uint8_t datatype = 0x00, const void *cookie = NULL);
+ uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES,
+ const void *cookie = nullptr);
+
void del_ret_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *key,
const size_t keylen, const uint32_t vb,
- const uint64_t cas = 0, const void *cookie = NULL);
+ const uint64_t cas = 0, const void *cookie = nullptr);
void set_degraded_mode(ENGINE_HANDLE *h,
ENGINE_HANDLE_V1 *h1,
itm_meta.exptime = info.exptime;
itm_meta.flags = info.flags;
set_with_meta(h, h1, key1, strlen(key1), val1, strlen(val1), 0, &itm_meta,
- last_cas, false, info.datatype, false, cookie);
+ last_cas, 0, info.datatype, cookie);
checkeq(ENGINE_SUCCESS,
h1->get(h, cookie, &itm, key1, strlen(key1), 0),
//SET_WITH_META
set_with_meta(h, h1, key, strlen(key), val, strlen(val), 0, &itm_meta,
- 0, false, datatype, false, cookie);
+ 0, 0, datatype, cookie);
checkeq(ENGINE_SUCCESS,
h1->get(h, cookie, &itm, key, strlen(key), 0),
const void *cookie = testHarness.create_cookie();
// delete an item with meta data
- del_with_meta(h, h1, key1, keylen, 0, &itemMeta, 0, false, false, cookie);
+ del_with_meta(h, h1, key1, keylen, 0, &itemMeta, 0/*cas*/, 0/*options*/, cookie);
check(last_uuid == vb_uuid, "Expected valid vbucket uuid");
check(last_seqno == high_seqno + 1, "Expected valid sequence number");
testHarness.set_mutation_extras_handling(cookie, false);
// delete an item with meta data
- del_with_meta(h, h1, key2, keylen, 0, &itemMeta, 0, false, false, cookie);
+ del_with_meta(h, h1, key2, keylen, 0, &itemMeta, 0/*cas*/, 0/*options*/, cookie);
check(last_uuid == vb_uuid, "Expected same vbucket uuid");
check(last_seqno == high_seqno + 1, "Expected same sequence number");
// do set with meta with the correct cas value. should pass.
set_with_meta(h, h1, key, keylen, newVal, newValLen, 0, &itm_meta, cas_for_set,
- false, 0, false, cookie);
+ 0, 0, cookie);
checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
check(last_uuid == vb_uuid, "Expected valid vbucket uuid");
check(last_seqno == high_seqno + 1, "Expected valid sequence number");
itm_meta.revSeqno++;
cas_for_set = last_meta.cas;
set_with_meta(h, h1, key, keylen, newVal, newValLen, 0, &itm_meta, cas_for_set,
- false, 0, false, cookie);
+ false, 0, cookie);
checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
check(last_uuid == vb_uuid, "Expected same vbucket uuid");
check(last_seqno == high_seqno + 1, "Expected same sequence number");
checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"),
"Expect zero setMeta ops");
- set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0, false,
- PROTOCOL_BINARY_RAW_BYTES, false);
+ set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS);
checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
checkeq(0, get_int_stat(h, h1, "ep_bg_meta_fetched"),
"Expected no bg meta fetchs, thanks to bloom filters");
// Check all meta data is the same
- set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0, false,
- PROTOCOL_BINARY_RAW_BYTES, false);
+ set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS);
checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
checkeq(1, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
"Expected set meta conflict resolution failure");
// Check that an older cas fails
itemMeta.cas = 0xdeadbeee;
- set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0, false,
- PROTOCOL_BINARY_RAW_BYTES, false);
+ set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS);
checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
checkeq(2, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
"Expected set meta conflict resolution failure");
// Check that a higher cas passes
itemMeta.cas = 0xdeadbeff;
- set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0, false,
- PROTOCOL_BINARY_RAW_BYTES, false);
+ set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS);
checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
+ // Check that we fail requests if the force flag is not set
+ itemMeta.cas = 0xdeadbeff + 1;
+ set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0,
+ 0/*options*/);
+ checkeq(PROTOCOL_BINARY_RESPONSE_EINVAL, last_status.load(), "Expected EINVAL");
+
return SUCCESS;
}
itemMeta.exptime = 0;
itemMeta.flags = 0xdeadbeef;
- del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, false, true);
+ // first check the command fails if no force is set
+ del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, 0/*options*/);
+ checkeq(PROTOCOL_BINARY_RESPONSE_EINVAL, last_status.load(), "Expected EINVAL");
+
+ del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, FORCE_ACCEPT_WITH_META_OPS);
checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
wait_for_flusher_to_settle(h, h1);
wait_for_stat_to_be(h, h1, "curr_items", 0);
// Check all meta data is the same
- del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, false, true);
+ del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, FORCE_ACCEPT_WITH_META_OPS);
checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
checkeq(1, get_int_stat(h, h1, "ep_num_ops_del_meta_res_fail"),
"Expected delete meta conflict resolution failure");
// Check that higher rev seqno but lower cas fails
itemMeta.cas = info.cas;
itemMeta.revSeqno = 11;
- del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, false, true);
+ del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, FORCE_ACCEPT_WITH_META_OPS);
checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
checkeq(2, get_int_stat(h, h1, "ep_num_ops_del_meta_res_fail"),
"Expected delete meta conflict resolution failure");
// Check that a higher cas and lower rev seqno passes
itemMeta.cas = info.cas + 2;
itemMeta.revSeqno = 9;
- del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, false, true);
+ del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, FORCE_ACCEPT_WITH_META_OPS);
checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected sucess");
return SUCCESS;
itm_meta.cas = 1;
}
set_with_meta(h, h1, key.data(), key.size(), NULL, 0, ii, &itm_meta,
- 0, false, PROTOCOL_BINARY_RAW_BYTES, true, 0);
+ 0, FORCE_ACCEPT_WITH_META_OPS);
checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
"Expected success");
}
ItemMetaData itm_meta;
itm_meta.cas = 1; // set to 1
set_with_meta(h, h1, key.data(), key.size(), NULL, 0, ii, &itm_meta,
- 0, false, PROTOCOL_BINARY_RAW_BYTES, true, 0);
+ 0, FORCE_ACCEPT_WITH_META_OPS);
checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
"Expected success");
}
itm_meta.cas = 2;
}
del_with_meta(h, h1, key.data(), key.size(), ii, &itm_meta,
- 1, false, PROTOCOL_BINARY_RAW_BYTES);
+ 1, FORCE_ACCEPT_WITH_META_OPS);
checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
"Expected success");
}
return SUCCESS;
}
+/*
+ * Perform set_with_meta and check CAS regeneration is ok.
+ */
+static enum test_result test_cas_regeneration(ENGINE_HANDLE *h,
+ ENGINE_HANDLE_V1 *h1) {
+
+ // First store a key from the past (small CAS).
+ ItemMetaData itemMeta;
+ itemMeta.revSeqno = 10;
+ itemMeta.cas = 0x1;
+ itemMeta.exptime = 0;
+ itemMeta.flags = 0xdeadbeef;
+ int force = 0;
+
+ if (strstr(testHarness.get_current_testcase()->cfg,
+ "conflict_resolution_type=lww") != nullptr) {
+ force = FORCE_ACCEPT_WITH_META_OPS;
+ }
+
+ // Set the key with a low CAS value
+ set_with_meta(h, h1, "key", 3, nullptr, 0, 0, &itemMeta, 0, force);
+ checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
+
+ check(get_meta(h, h1, "key"), "Failed to get_meta");
+
+ // CAS must be what we set.
+ checkeq(itemMeta.cas, last_meta.cas, "CAS is not the value we stored");
+
+ itemMeta.cas++;
+
+ // Check that the code requires skip
+ set_with_meta(h, h1, "key", 3, nullptr, 0, 0, &itemMeta, 0,
+ REGENERATE_CAS/*but no skip*/);
+ checkeq(PROTOCOL_BINARY_RESPONSE_EINVAL, last_status.load(),
+ "Expected EINVAL");
+
+ set_with_meta(h, h1, "key", 3, nullptr, 0, 0, &itemMeta, 0,
+ REGENERATE_CAS|SKIP_CONFLICT_RESOLUTION_FLAG);
+
+ checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
+ "Expected success");
+
+ check(get_meta(h, h1, "key"), "Failed to get_meta");
+
+ uint64_t cas = last_meta.cas;
+ // Check item has a new CAS
+ checkne(itemMeta.cas, cas, "CAS was not regenerated");
+
+ itemMeta.cas++;
+ // All flags set should still regen the cas (lww and seqno)
+ set_with_meta(h, h1, "key", 3, nullptr, 0, 0, &itemMeta, 0,
+ REGENERATE_CAS|SKIP_CONFLICT_RESOLUTION_FLAG|force);
+
+ checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
+ "Expected success");
+
+ check(get_meta(h, h1, "key"), "Failed to get_meta");
+ // Check item has a new CAS
+ checkne(itemMeta.cas, last_meta.cas, "CAS was not regenerated");
+ checkne(cas, last_meta.cas, "CAS was not regenerated");
+ return SUCCESS;
+}
+
+/*
+ * Test that we can send options and nmeta
+ * The nmeta is just going to be ignored though, but should not fail
+ */
+static enum test_result test_cas_options_and_nmeta(ENGINE_HANDLE *h,
+ ENGINE_HANDLE_V1 *h1) {
+ ItemMetaData itemMeta;
+ itemMeta.revSeqno = 10;
+ itemMeta.cas = 0x1;
+ itemMeta.exptime = 0;
+ itemMeta.flags = 0xdeadbeef;
+
+ // Watson (4.6) accepts valid encodings, but ignores them
+ std::vector<char> junkMeta = {-2,-1,2,3};
+
+ // Set the key and junk nmeta
+ set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS, PROTOCOL_BINARY_RAW_BYTES,
+ nullptr, junkMeta);
+ checkeq(PROTOCOL_BINARY_RESPONSE_EINVAL, last_status.load(), "Expected EINVAL");
+
+ // Set the key and junk nmeta that's quite large
+ junkMeta.resize(std::numeric_limits<uint16_t>::max());
+ set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS, PROTOCOL_BINARY_RAW_BYTES,
+ nullptr, junkMeta);
+ checkeq(PROTOCOL_BINARY_RESPONSE_EINVAL, last_status.load(), "Expected EINVAL");
+
+ // Test that valid meta can be sent. It should be ignored and success
+ // returned
+ // Encodings which should not fail, see ext_meta_parser.cc
+#pragma pack(1)
+ struct adjusted_time_metadata {
+ uint8_t type;
+ uint16_t length;
+ int64_t value;
+ };
+ struct conf_res_metadata {
+ uint8_t type;
+ uint16_t length;
+ uint8_t value;
+ };
+ struct with_cas_metadata1 {
+ uint8_t version;
+ adjusted_time_metadata adjusted_time;
+ };
+ struct with_cas_metadata2 {
+ uint8_t version;
+ conf_res_metadata conf_res;
+ };
+ struct with_cas_metadata3 {
+ uint8_t version;
+ conf_res_metadata conf_res;
+ adjusted_time_metadata adjusted_time;
+ };
+ struct with_cas_metadata4 {
+ uint8_t version;
+ adjusted_time_metadata adjusted_time;
+ conf_res_metadata conf_res;
+ };
+#pragma pack()
+
+ {
+ with_cas_metadata1 validMetaData = {META_EXT_VERSION_ONE,
+ {CMD_META_ADJUSTED_TIME,
+ htons(sizeof(int64_t)), -1}};
+ std::vector<char> validMetaVector(reinterpret_cast<char*>(&validMetaData),
+ reinterpret_cast<char*>(&validMetaData) +
+ sizeof(validMetaData));
+
+ // Set the key with a low CAS value and real nmeta
+ set_with_meta(h, h1, "key1", 4, nullptr, 0, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS, PROTOCOL_BINARY_RAW_BYTES,
+ nullptr, validMetaVector);
+ checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
+ "Expected success");
+
+ itemMeta.cas++;
+ del_with_meta(h, h1, "key1", 4, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS, nullptr, validMetaVector);
+ checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
+ "Expected success");
+ }
+
+ {
+ with_cas_metadata2 validMetaData = {META_EXT_VERSION_ONE,
+ {CMD_META_CONFLICT_RES_MODE,
+ htons(sizeof(uint8_t)), 0xff}};
+ std::vector<char> validMetaVector(reinterpret_cast<char*>(&validMetaData),
+ reinterpret_cast<char*>(&validMetaData) +
+ sizeof(validMetaData));
+
+ // Set the key with a low CAS value and real nmeta
+ set_with_meta(h, h1, "key2", 4, nullptr, 0, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS, PROTOCOL_BINARY_RAW_BYTES,
+ nullptr, validMetaVector);
+ checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
+ "Expected success");
+
+ itemMeta.cas++;
+ del_with_meta(h, h1, "key2", 4, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS, nullptr, validMetaVector);
+ checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
+ "Expected success");
+ }
+
+ {
+ with_cas_metadata3 validMetaData = {META_EXT_VERSION_ONE,
+ {CMD_META_CONFLICT_RES_MODE,
+ htons(sizeof(uint8_t)), 0xff},
+ {CMD_META_ADJUSTED_TIME,
+ htons(sizeof(int64_t)), -1}};
+ std::vector<char> validMetaVector(reinterpret_cast<char*>(&validMetaData),
+ reinterpret_cast<char*>(&validMetaData) +
+ sizeof(validMetaData));
+
+ // Set the key with a low CAS value and real nmeta
+ set_with_meta(h, h1, "key3", 4, nullptr, 0, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS, PROTOCOL_BINARY_RAW_BYTES,
+ nullptr, validMetaVector);
+ checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
+ "Expected success");
+
+ itemMeta.cas++;
+ del_with_meta(h, h1, "key3", 4, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS, nullptr, validMetaVector);
+ checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
+ "Expected success");
+ }
+
+ {
+ with_cas_metadata4 validMetaData = {META_EXT_VERSION_ONE,
+ {CMD_META_ADJUSTED_TIME,
+ htons(sizeof(int64_t)), -1},
+ {CMD_META_CONFLICT_RES_MODE,
+ htons(sizeof(uint8_t)), 0xff}};
+ std::vector<char> validMetaVector(reinterpret_cast<char*>(&validMetaData),
+ reinterpret_cast<char*>(&validMetaData) +
+ sizeof(validMetaData));
+
+ // Set the key with a low CAS value and real nmeta
+ set_with_meta(h, h1, "key4", 4, NULL, 0, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS, PROTOCOL_BINARY_RAW_BYTES,
+ nullptr, validMetaVector);
+ checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
+ "Expected success");
+
+ itemMeta.cas++;
+ del_with_meta(h, h1, "key4", 4, 0, &itemMeta, 0,
+ FORCE_ACCEPT_WITH_META_OPS, nullptr, validMetaVector);
+ checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
+ "Expected success");
+ }
+
+ return SUCCESS;
+}
+
// Test manifest //////////////////////////////////////////////////////////////
const char *default_dbname = "./ep_testsuite_xdcr";
test_setting_drift_threshold, test_setup,
teardown, nullptr,
prepare, cleanup),
+ TestCase("test CAS regeneration lww",
+ test_cas_regeneration, test_setup, teardown,
+ "conflict_resolution_type=lww",
+ prepare, cleanup),
+ TestCase("test CAS regeneration seqno",
+ test_cas_regeneration, test_setup, teardown,
+ "conflict_resolution_type=seqno",
+ prepare, cleanup),
+ TestCase("test CAS options and nmeta",
+ test_cas_options_and_nmeta, test_setup, teardown,
+ "conflict_resolution_type=lww",
+ prepare, cleanup),
TestCase(NULL, NULL, NULL, NULL, NULL, prepare, cleanup)
};