#include <sys/param.h>
#include <string.h>
#include "unittest.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "heap.h"
#include "alloc_class.h"
#include "obj.h"
#include "util.h"
#ifdef __cplusplus
}
#endif
#define MAX_ALLOC_MUL 8
#define MAX_ALLOC_CLASS 5
POBJ_LAYOUT_BEGIN(realloc);
POBJ_LAYOUT_ROOT(realloc, struct root);
POBJ_LAYOUT_TOID(realloc, struct object);
POBJ_LAYOUT_END(realloc);
struct object {
size_t value;
char data[];
};
struct root {
TOID(struct object) obj;
char data[CHUNKSIZE - sizeof(TOID(struct object))];
};
static struct alloc_class_collection *alloc_classes;
static void
test_alloc(PMEMobjpool *pop, size_t size)
{
TOID(struct root) root = POBJ_ROOT(pop, struct root);
UT_ASSERT(TOID_IS_NULL(D_RO(root)->obj));
int ret = pmemobj_realloc(pop, &D_RW(root)->obj.oid, size,
TOID_TYPE_NUM(struct object));
UT_ASSERTeq(ret, 0);
UT_ASSERT(!TOID_IS_NULL(D_RO(root)->obj));
UT_ASSERT(pmemobj_alloc_usable_size(D_RO(root)->obj.oid) >= size);
}
static void
test_free(PMEMobjpool *pop)
{
TOID(struct root) root = POBJ_ROOT(pop, struct root);
UT_ASSERT(!TOID_IS_NULL(D_RO(root)->obj));
int ret = pmemobj_realloc(pop, &D_RW(root)->obj.oid, 0,
TOID_TYPE_NUM(struct object));
UT_ASSERTeq(ret, 0);
UT_ASSERT(TOID_IS_NULL(D_RO(root)->obj));
}
static int check_integrity = 1;
static uint16_t
fill_buffer(unsigned char *buf, size_t size)
{
for (size_t i = 0; i < size; ++i)
buf[i] = rand() % 255;
pmem_persist(buf, size);
return ut_checksum(buf, size);
}
static void
test_realloc(PMEMobjpool *pop, size_t size_from, size_t size_to,
unsigned type_from, unsigned type_to, int zrealloc)
{
TOID(struct root) root = POBJ_ROOT(pop, struct root);
UT_ASSERT(TOID_IS_NULL(D_RO(root)->obj));
int ret;
if (zrealloc)
ret = pmemobj_zalloc(pop, &D_RW(root)->obj.oid,
size_from, type_from);
else
ret = pmemobj_alloc(pop, &D_RW(root)->obj.oid,
size_from, type_from, NULL, NULL);
UT_ASSERTeq(ret, 0);
UT_ASSERT(!TOID_IS_NULL(D_RO(root)->obj));
size_t usable_size_from =
pmemobj_alloc_usable_size(D_RO(root)->obj.oid);
UT_ASSERT(usable_size_from >= size_from);
size_t check_size;
uint16_t checksum;
if (zrealloc) {
UT_ASSERT(util_is_zeroed(D_RO(D_RO(root)->obj),
size_from));
} else if (check_integrity) {
check_size = size_to >= usable_size_from ?
usable_size_from : size_to;
checksum = fill_buffer((unsigned char *)D_RW(D_RW(root)->obj),
check_size);
}
if (zrealloc) {
ret = pmemobj_zrealloc(pop, &D_RW(root)->obj.oid,
size_to, type_to);
} else {
ret = pmemobj_realloc(pop, &D_RW(root)->obj.oid,
size_to, type_to);
}
UT_ASSERTeq(ret, 0);
UT_ASSERT(!TOID_IS_NULL(D_RO(root)->obj));
size_t usable_size_to =
pmemobj_alloc_usable_size(D_RO(root)->obj.oid);
UT_ASSERT(usable_size_to >= size_to);
if (size_to < size_from) {
UT_ASSERT(usable_size_to <= usable_size_from);
}
if (zrealloc) {
UT_ASSERT(util_is_zeroed(D_RO(D_RO(root)->obj), size_to));
} else if (check_integrity) {
uint16_t checksum2 = ut_checksum(
(uint8_t *)D_RW(D_RW(root)->obj), check_size);
if (checksum2 != checksum)
UT_ASSERTinfo(0, "memory corruption");
}
pmemobj_free(&D_RW(root)->obj.oid);
UT_ASSERT(TOID_IS_NULL(D_RO(root)->obj));
}
static void
test_realloc_sizes(PMEMobjpool *pop, unsigned type_from,
unsigned type_to, int zrealloc, int size_diff)
{
for (uint8_t i = 0; i < MAX_ALLOCATION_CLASSES; ++i) {
struct alloc_class *c = alloc_class_by_id(alloc_classes, i);
if (c == NULL)
continue;
size_t header_size = header_type_to_size[c->header_type];
size_t size_from = c->unit_size - header_size - size_diff;
for (int j = 2; j <= MAX_ALLOC_MUL; j++) {
size_t inc_size_to = c->unit_size * j - header_size;
test_realloc(pop, size_from, inc_size_to,
type_from, type_to, zrealloc);
size_t dec_size_to = c->unit_size / j;
if (dec_size_to <= header_size)
dec_size_to = header_size;
else
dec_size_to -= header_size;
test_realloc(pop, size_from, dec_size_to,
type_from, type_to, zrealloc);
for (int k = 0; k < MAX_ALLOC_CLASS; k++) {
struct alloc_class *ck = alloc_class_by_id(
alloc_classes, k);
if (c == NULL)
continue;
size_t header_sizek =
header_type_to_size[c->header_type];
size_t prev_size = ck->unit_size - header_sizek;
test_realloc(pop, size_from, prev_size,
type_from, type_to, zrealloc);
}
}
}
}
int
main(int argc, char *argv[])
{
START(argc, argv, "obj_realloc");
UT_COMPILE_ERROR_ON(POBJ_LAYOUT_TYPES_NUM(realloc) != 1);
if (argc < 2)
UT_FATAL("usage: %s file [check_integrity]", argv[0]);
PMEMobjpool *pop = pmemobj_open(argv[1], POBJ_LAYOUT_NAME(realloc));
if (!pop)
UT_FATAL("!pmemobj_open");
if (argc >= 3)
check_integrity = atoi(argv[2]);
alloc_classes = alloc_class_collection_new();
test_alloc(pop, 16);
test_free(pop);
test_realloc_sizes(pop, 0, 0, 0, 0);
test_realloc_sizes(pop, 0, 1, 0, 0);
test_realloc_sizes(pop, 0, 0, 1, 8);
test_realloc_sizes(pop, 0, 0, 1, 0);
test_realloc_sizes(pop, 0, 1, 1, 8);
test_realloc_sizes(pop, 0, 1, 1, 0);
alloc_class_collection_delete(alloc_classes);
pmemobj_close(pop);
DONE(NULL);
}
#ifdef _MSC_VER
extern "C" {
MSVC_CONSTR(libpmemobj_init)
MSVC_DESTR(libpmemobj_fini)
}
#endif