#include <sys/param.h>
#include <string.h>
#include "unittest.h"
#include "util.h"
#include "valgrind_internal.h"
#define LAYOUT_NAME "tx_free"
#define OBJ_SIZE (200 * 1024)
enum type_number {
TYPE_FREE_NO_TX,
TYPE_FREE_WRONG_UUID,
TYPE_FREE_COMMIT,
TYPE_FREE_ABORT,
TYPE_FREE_COMMIT_NESTED1,
TYPE_FREE_COMMIT_NESTED2,
TYPE_FREE_ABORT_NESTED1,
TYPE_FREE_ABORT_NESTED2,
TYPE_FREE_ABORT_AFTER_NESTED1,
TYPE_FREE_ABORT_AFTER_NESTED2,
TYPE_FREE_OOM,
TYPE_FREE_ALLOC,
TYPE_FREE_AFTER_ABORT,
TYPE_FREE_MANY_TIMES,
};
TOID_DECLARE(struct object, 0);
struct object {
size_t value;
char data[OBJ_SIZE - sizeof(size_t)];
};
static PMEMoid
do_tx_alloc(PMEMobjpool *pop, int type_num)
{
PMEMoid ret = OID_NULL;
TX_BEGIN(pop) {
ret = pmemobj_tx_alloc(sizeof(struct object), type_num);
} TX_END
return ret;
}
static void
do_tx_free_wrong_uuid(PMEMobjpool *pop)
{
volatile int ret = 0;
PMEMoid oid = do_tx_alloc(pop, TYPE_FREE_WRONG_UUID);
oid.pool_uuid_lo = ~oid.pool_uuid_lo;
TX_BEGIN(pop) {
ret = pmemobj_tx_free(oid);
UT_ASSERTeq(ret, 0);
} TX_ONABORT {
ret = -1;
} TX_END
UT_ASSERTeq(ret, -1);
TOID(struct object) obj;
TOID_ASSIGN(obj, POBJ_FIRST_TYPE_NUM(pop, TYPE_FREE_WRONG_UUID));
UT_ASSERT(!TOID_IS_NULL(obj));
}
static void
do_tx_free_null_oid(PMEMobjpool *pop)
{
volatile int ret = 0;
TX_BEGIN(pop) {
ret = pmemobj_tx_free(OID_NULL);
} TX_ONABORT {
ret = -1;
} TX_END
UT_ASSERTeq(ret, 0);
}
static void
do_tx_free_commit(PMEMobjpool *pop)
{
int ret;
PMEMoid oid = do_tx_alloc(pop, TYPE_FREE_COMMIT);
TX_BEGIN(pop) {
ret = pmemobj_tx_free(oid);
UT_ASSERTeq(ret, 0);
} TX_ONABORT {
UT_ASSERT(0);
} TX_END
TOID(struct object) obj;
TOID_ASSIGN(obj, POBJ_FIRST_TYPE_NUM(pop, TYPE_FREE_COMMIT));
UT_ASSERT(TOID_IS_NULL(obj));
}
static void
do_tx_free_abort(PMEMobjpool *pop)
{
int ret;
PMEMoid oid = do_tx_alloc(pop, TYPE_FREE_ABORT);
TX_BEGIN(pop) {
ret = pmemobj_tx_free(oid);
UT_ASSERTeq(ret, 0);
pmemobj_tx_abort(-1);
} TX_ONCOMMIT {
UT_ASSERT(0);
} TX_END
TOID(struct object) obj;
TOID_ASSIGN(obj, POBJ_FIRST_TYPE_NUM(pop, TYPE_FREE_ABORT));
UT_ASSERT(!TOID_IS_NULL(obj));
}
static void
do_tx_free_commit_nested(PMEMobjpool *pop)
{
int ret;
PMEMoid oid1 = do_tx_alloc(pop, TYPE_FREE_COMMIT_NESTED1);
PMEMoid oid2 = do_tx_alloc(pop, TYPE_FREE_COMMIT_NESTED2);
TX_BEGIN(pop) {
ret = pmemobj_tx_free(oid1);
UT_ASSERTeq(ret, 0);
TX_BEGIN(pop) {
ret = pmemobj_tx_free(oid2);
UT_ASSERTeq(ret, 0);
} TX_ONABORT {
UT_ASSERT(0);
} TX_END
} TX_ONABORT {
UT_ASSERT(0);
} TX_END
TOID(struct object) obj;
TOID_ASSIGN(obj, POBJ_FIRST_TYPE_NUM(pop, TYPE_FREE_COMMIT_NESTED1));
UT_ASSERT(TOID_IS_NULL(obj));
TOID_ASSIGN(obj, POBJ_FIRST_TYPE_NUM(pop, TYPE_FREE_COMMIT_NESTED2));
UT_ASSERT(TOID_IS_NULL(obj));
}
static void
do_tx_free_abort_nested(PMEMobjpool *pop)
{
int ret;
PMEMoid oid1 = do_tx_alloc(pop, TYPE_FREE_ABORT_NESTED1);
PMEMoid oid2 = do_tx_alloc(pop, TYPE_FREE_ABORT_NESTED2);
TX_BEGIN(pop) {
ret = pmemobj_tx_free(oid1);
UT_ASSERTeq(ret, 0);
TX_BEGIN(pop) {
ret = pmemobj_tx_free(oid2);
UT_ASSERTeq(ret, 0);
pmemobj_tx_abort(-1);
} TX_ONCOMMIT {
UT_ASSERT(0);
} TX_END
} TX_ONCOMMIT {
UT_ASSERT(0);
} TX_END
TOID(struct object) obj;
TOID_ASSIGN(obj, POBJ_FIRST_TYPE_NUM(pop, TYPE_FREE_ABORT_NESTED1));
UT_ASSERT(!TOID_IS_NULL(obj));
TOID_ASSIGN(obj, POBJ_FIRST_TYPE_NUM(pop, TYPE_FREE_ABORT_NESTED2));
UT_ASSERT(!TOID_IS_NULL(obj));
}
static void
do_tx_free_abort_after_nested(PMEMobjpool *pop)
{
int ret;
PMEMoid oid1 = do_tx_alloc(pop, TYPE_FREE_ABORT_AFTER_NESTED1);
PMEMoid oid2 = do_tx_alloc(pop, TYPE_FREE_ABORT_AFTER_NESTED2);
TX_BEGIN(pop) {
ret = pmemobj_tx_free(oid1);
UT_ASSERTeq(ret, 0);
TX_BEGIN(pop) {
ret = pmemobj_tx_free(oid2);
UT_ASSERTeq(ret, 0);
} TX_END
pmemobj_tx_abort(-1);
} TX_ONCOMMIT {
UT_ASSERT(0);
} TX_END
TOID(struct object) obj;
TOID_ASSIGN(obj, POBJ_FIRST_TYPE_NUM(pop,
TYPE_FREE_ABORT_AFTER_NESTED1));
UT_ASSERT(!TOID_IS_NULL(obj));
TOID_ASSIGN(obj, POBJ_FIRST_TYPE_NUM(pop,
TYPE_FREE_ABORT_AFTER_NESTED2));
UT_ASSERT(!TOID_IS_NULL(obj));
}
static void
do_tx_free_alloc_abort(PMEMobjpool *pop)
{
int ret;
TOID(struct object) obj;
TX_BEGIN(pop) {
TOID_ASSIGN(obj, pmemobj_tx_alloc(
sizeof(struct object), TYPE_FREE_ALLOC));
UT_ASSERT(!TOID_IS_NULL(obj));
ret = pmemobj_tx_free(obj.oid);
UT_ASSERTeq(ret, 0);
pmemobj_tx_abort(-1);
} TX_ONCOMMIT {
UT_ASSERT(0);
} TX_END
TOID_ASSIGN(obj, POBJ_FIRST_TYPE_NUM(pop, TYPE_FREE_ALLOC));
UT_ASSERT(TOID_IS_NULL(obj));
}
static void
do_tx_free_alloc_commit(PMEMobjpool *pop)
{
int ret;
TOID(struct object) obj;
TX_BEGIN(pop) {
TOID_ASSIGN(obj, pmemobj_tx_alloc(
sizeof(struct object), TYPE_FREE_ALLOC));
UT_ASSERT(!TOID_IS_NULL(obj));
ret = pmemobj_tx_free(obj.oid);
UT_ASSERTeq(ret, 0);
} TX_ONABORT {
UT_ASSERT(0);
} TX_END
TOID_ASSIGN(obj, POBJ_FIRST_TYPE_NUM(pop, TYPE_FREE_ALLOC));
UT_ASSERT(TOID_IS_NULL(obj));
}
static void
do_tx_free_abort_free(PMEMobjpool *pop)
{
PMEMoid oid = do_tx_alloc(pop, TYPE_FREE_AFTER_ABORT);
TX_BEGIN(pop) {
pmemobj_tx_free(oid);
pmemobj_tx_abort(-1);
} TX_ONCOMMIT {
UT_ASSERT(0);
} TX_END
TX_BEGIN(pop) {
pmemobj_tx_free(oid);
} TX_ONABORT {
UT_ASSERT(0);
} TX_END
}
static void
do_tx_free_many_times(PMEMobjpool *pop)
{
#define TX_FREE_COUNT ((1 << 3) + 1)
PMEMoid oids[TX_FREE_COUNT];
for (int i = 0; i < TX_FREE_COUNT; ++i)
oids[i] = do_tx_alloc(pop, TYPE_FREE_MANY_TIMES);
TX_BEGIN(pop) {
for (int i = 0; i < TX_FREE_COUNT; ++i)
pmemobj_tx_free(oids[i]);
} TX_ONABORT {
UT_ASSERT(0);
} TX_END
#undef TX_FREE_COUNT
}
int
main(int argc, char *argv[])
{
START(argc, argv, "obj_tx_free");
util_init();
if (argc != 2)
UT_FATAL("usage: %s [file]", argv[0]);
PMEMobjpool *pop;
if ((pop = pmemobj_create(argv[1], LAYOUT_NAME, PMEMOBJ_MIN_POOL,
S_IWUSR | S_IRUSR)) == NULL)
UT_FATAL("!pmemobj_create");
do_tx_free_wrong_uuid(pop);
VALGRIND_WRITE_STATS;
do_tx_free_null_oid(pop);
VALGRIND_WRITE_STATS;
do_tx_free_commit(pop);
VALGRIND_WRITE_STATS;
do_tx_free_abort(pop);
VALGRIND_WRITE_STATS;
do_tx_free_commit_nested(pop);
VALGRIND_WRITE_STATS;
do_tx_free_abort_nested(pop);
VALGRIND_WRITE_STATS;
do_tx_free_abort_after_nested(pop);
VALGRIND_WRITE_STATS;
do_tx_free_alloc_commit(pop);
VALGRIND_WRITE_STATS;
do_tx_free_alloc_abort(pop);
VALGRIND_WRITE_STATS;
do_tx_free_abort_free(pop);
VALGRIND_WRITE_STATS;
do_tx_free_many_times(pop);
VALGRIND_WRITE_STATS;
pmemobj_close(pop);
DONE(NULL);
}