#include "mctest.h"
class McAlloc : public ::testing::Test {
protected:
mc_CMDQUEUE cQueue;
void setupPipeline(mc_PIPELINE *pipeline) {
mcreq_queue_init(&cQueue);
mcreq_pipeline_init(pipeline);
pipeline->parent = &cQueue;
}
};
TEST_F(McAlloc, testPipelineFreeAlloc)
{
mc_PIPELINE pipeline;
memset(&pipeline, 0, sizeof(pipeline));
mcreq_pipeline_init(&pipeline);
mcreq_pipeline_cleanup(&pipeline);
}
TEST_F(McAlloc, testPacketFreeAlloc)
{
mc_PIPELINE pipeline;
mc_PACKET *copied = NULL;
memset(&pipeline, 0, sizeof(pipeline));
setupPipeline(&pipeline);
mc_PACKET *packet = mcreq_allocate_packet(&pipeline);
ASSERT_TRUE(packet != NULL);
mcreq_reserve_header(&pipeline, packet, 24);
copied = mcreq_renew_packet(packet);
mcreq_wipe_packet(&pipeline, packet);
mcreq_release_packet(&pipeline, packet);
mcreq_pipeline_cleanup(&pipeline);
memset(SPAN_BUFFER(&copied->kh_span), 0xff, copied->kh_span.size);
mcreq_wipe_packet(NULL, copied);
mcreq_release_packet(NULL, copied);
}
struct dummy_datum {
mc_EPKTDATUM base;
int refcount;
};
extern "C" {
static void datum_free(mc_EPKTDATUM *epd) {
dummy_datum *dd = (dummy_datum *)epd;
dd->refcount--;
}
}
TEST_F(McAlloc, testExdataAlloc)
{
mc_PIPELINE pipeline;
mc_PACKET *copy1, *copy2;
setupPipeline(&pipeline);
mc_PACKET *packet = mcreq_allocate_packet(&pipeline);
mcreq_reserve_header(&pipeline, packet, 24);
copy1 = mcreq_renew_packet(packet);
ASSERT_FALSE((copy1->flags & MCREQ_F_DETACHED) == 0);
dummy_datum dd;
dd.base.key = "Dummy";
dd.base.dtorfn = datum_free;
dd.refcount = 1;
mcreq_epkt_insert((mc_EXPACKET*)copy1, &dd.base);
mc_EPKTDATUM *epd = mcreq_epkt_find((mc_EXPACKET*)copy1, "Dummy");
ASSERT_FALSE(epd == NULL);
ASSERT_TRUE(epd == &dd.base);
copy2 = mcreq_renew_packet(copy1);
epd = mcreq_epkt_find((mc_EXPACKET*)copy1, "Dummy");
ASSERT_TRUE(epd == NULL);
epd = mcreq_epkt_find((mc_EXPACKET*)copy2, "Dummy");
ASSERT_FALSE(epd == NULL);
mcreq_wipe_packet(&pipeline, packet);
mcreq_release_packet(&pipeline, packet);
mcreq_wipe_packet(NULL, copy1);
mcreq_release_packet(NULL, copy1);
mcreq_wipe_packet(NULL, copy2);
mcreq_release_packet(NULL, copy2);
ASSERT_EQ(0, dd.refcount);
mcreq_pipeline_cleanup(&pipeline);
}
TEST_F(McAlloc, testKeyAlloc)
{
CQWrap q;
mc_PACKET *packet;
mc_PIPELINE *pipeline;
lcb_CMDBASE cmd;
protocol_binary_request_header hdr;
memset(&cmd, 0, sizeof(cmd));
memset(&hdr, 0, sizeof(hdr));
cmd.key.contig.bytes = const_cast<char *>("Hello");
cmd.key.contig.nbytes = 5;
lcb_error_t ret;
ret = mcreq_basic_packet(&q, &cmd, &hdr, 0, &packet, &pipeline, 0);
ASSERT_EQ(LCB_SUCCESS, ret);
ASSERT_TRUE(packet != NULL);
ASSERT_TRUE(pipeline != NULL);
ASSERT_EQ(5, ntohs(hdr.request.keylen));
int vb = lcbvb_k2vb(q.config, "Hello", 5);
ASSERT_EQ(vb, ntohs(hdr.request.vbucket));
memcpy(SPAN_BUFFER(&packet->kh_span), &hdr, sizeof(hdr));
lcb_VALBUF vreq;
memset(&vreq, 0, sizeof(vreq));
const void *key;
lcb_size_t nkey;
mcreq_get_key(packet, &key, &nkey);
ASSERT_EQ(5, nkey);
ASSERT_EQ(0, memcmp(key, "Hello", 5));
mcreq_wipe_packet(pipeline, packet);
mcreq_release_packet(pipeline, packet);
}
TEST_F(McAlloc, testValueAlloc)
{
CQWrap q;
mc_PACKET *packet;
mc_PIPELINE *pipeline;
lcb_CMDBASE cmd;
protocol_binary_request_header hdr;
lcb_VALBUF vreq;
memset(&cmd, 0, sizeof(cmd));
memset(&hdr, 0, sizeof(hdr));
memset(&vreq, 0, sizeof(vreq));
const char *key = "Hello";
const char *value = "World";
lcb_error_t ret;
cmd.key.contig.bytes = const_cast<char *>(key);
cmd.key.contig.nbytes = 5;
vreq.u_buf.contig.bytes = const_cast<char *>(value);
vreq.u_buf.contig.nbytes = 5;
ret = mcreq_basic_packet(&q, &cmd, &hdr, 0, &packet, &pipeline, 0);
ASSERT_EQ(LCB_SUCCESS, ret);
ret = mcreq_reserve_value(pipeline, packet, &vreq);
ASSERT_EQ(ret, LCB_SUCCESS);
ASSERT_EQ(packet->flags, MCREQ_F_HASVALUE);
ASSERT_EQ(0, memcmp(SPAN_BUFFER(&packet->u_value.single), value, 5));
ASSERT_NE(SPAN_BUFFER(&packet->u_value.single), value);
mcreq_wipe_packet(pipeline, packet);
mcreq_release_packet(pipeline, packet);
ret = mcreq_basic_packet(&q, &cmd, &hdr, 0, &packet, &pipeline, 0);
ASSERT_EQ(ret, LCB_SUCCESS);
vreq.vtype = LCB_KV_CONTIG;
ret = mcreq_reserve_value(pipeline, packet, &vreq);
ASSERT_EQ(SPAN_BUFFER(&packet->u_value.single), value);
ASSERT_EQ(MCREQ_F_HASVALUE|MCREQ_F_VALUE_NOCOPY, packet->flags);
mcreq_wipe_packet(pipeline, packet);
mcreq_release_packet(pipeline, packet);
nb_IOV iov[2];
iov[0].iov_base = (void *)value;
iov[0].iov_len = 3;
iov[1].iov_base = (void *)(value + 3);
iov[1].iov_len = 2;
vreq.u_buf.multi.iov = (lcb_IOV *)iov;
vreq.u_buf.multi.niov = 2;
vreq.vtype = LCB_KV_IOV;
ret = mcreq_basic_packet(&q, &cmd, &hdr, 0, &packet, &pipeline, 0);
ASSERT_EQ(LCB_SUCCESS, ret);
ret = mcreq_reserve_value(pipeline, packet, &vreq);
ASSERT_EQ(LCB_SUCCESS, ret);
ASSERT_EQ(MCREQ_F_HASVALUE|MCREQ_F_VALUE_IOV|MCREQ_F_VALUE_NOCOPY,
packet->flags);
ASSERT_NE(&iov[0], (nb_IOV *)packet->u_value.multi.iov);
ASSERT_EQ(2, packet->u_value.multi.niov);
ASSERT_EQ(5, packet->u_value.multi.total_length);
mcreq_wipe_packet(pipeline, packet);
mcreq_release_packet(pipeline, packet);
iov[0].iov_base = (void *)value;
iov[0].iov_len = 3;
iov[1].iov_base = (void *)(value + 3);
iov[1].iov_len = 2;
vreq.u_buf.multi.iov = (lcb_IOV *)iov;
vreq.u_buf.multi.niov = 2;
vreq.u_buf.multi.total_length = 0;
vreq.vtype = LCB_KV_IOVCOPY;
ret = mcreq_basic_packet(&q, &cmd, &hdr, 0, &packet, &pipeline, 0);
ASSERT_EQ(LCB_SUCCESS, ret);
ret = mcreq_reserve_value(pipeline, packet, &vreq);
ASSERT_EQ(LCB_SUCCESS, ret);
ASSERT_EQ(MCREQ_F_HASVALUE, packet->flags);
ASSERT_EQ(0, memcmp(SPAN_BUFFER(&packet->u_value.single), value, 5));
mcreq_wipe_packet(pipeline, packet);
mcreq_release_packet(pipeline, packet);
}
struct ExtraCookie {
mc_REQDATAEX base;
int remaining;
};
extern "C" {
static void pkt_dtor(mc_PACKET *pkt) {
mc_REQDATAEX *rd = pkt->u_rdata.exdata;
ExtraCookie *ec = (ExtraCookie *)rd;
ec->remaining--;
}
}
TEST_F(McAlloc, testRdataExDtor)
{
CQWrap q;
lcb_CMDBASE basecmd;
ExtraCookie ec;
protocol_binary_request_header hdr;
memset(&hdr, 0, sizeof hdr);
memset(&basecmd, 0, sizeof basecmd);
memset(&ec, 0, sizeof ec);
mc_REQDATAPROCS procs = { NULL, pkt_dtor };
ec.base.procs = &procs;
basecmd.key.contig.bytes = "foo";
basecmd.key.contig.nbytes = 3;
mcreq_sched_enter(&q);
for (unsigned ii = 0; ii < 5; ii++) {
lcb_error_t err;
mc_PIPELINE *pl;
mc_PACKET *pkt;
err = mcreq_basic_packet(&q, &basecmd, &hdr, 0, &pkt, &pl, 0);
ASSERT_EQ(LCB_SUCCESS, err);
pkt->flags |= MCREQ_F_REQEXT;
pkt->u_rdata.exdata = &ec.base;
mcreq_sched_add(pl, pkt);
ec.remaining++;
}
mcreq_sched_fail(&q);
ASSERT_EQ(0, ec.remaining);
}