/*
* Copyright 2016-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* array.c -- example of arrays usage
*/
#include <ex_common.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/stat.h>
#include <libpmemobj.h>
#define TOID_ARRAY(x) TOID(x)
#define COUNT_OF(x) (sizeof(x) / sizeof(x[0]))
#define MAX_BUFFLEN 30
#define MAX_TYPE_NUM 8
POBJ_LAYOUT_BEGIN(array);
POBJ_LAYOUT_TOID(array, struct array_elm);
POBJ_LAYOUT_TOID(array, int);
POBJ_LAYOUT_TOID(array, PMEMoid);
POBJ_LAYOUT_TOID(array, TOID(struct array_elm));
POBJ_LAYOUT_TOID(array, struct array_info);
POBJ_LAYOUT_END(array);
static PMEMobjpool *pop;
enum array_types {
UNKNOWN_ARRAY_TYPE,
INT_ARRAY_TYPE,
PMEMOID_ARRAY_TYPE,
TOID_ARRAY_TYPE,
MAX_ARRAY_TYPE
};
struct array_elm {
int id;
};
struct array_info {
char name[MAX_BUFFLEN];
size_t size;
enum array_types type;
PMEMoid array;
};
/*
* print_usage -- print general usage
*/
static void
print_usage(void)
{
printf("usage: ./array <file-name> "
"<alloc|realloc|free|print>"
" <array-name> [<size> [<TOID|PMEMoid|int>]]\n");
}
/*
* get type -- parse argument given as type of array
*/
static enum array_types
get_type(const char *type_name)
{
const char *names[MAX_ARRAY_TYPE] = {"", "int", "PMEMoid", "TOID"};
enum array_types type;
for (type = (enum array_types)(MAX_ARRAY_TYPE - 1);
type > UNKNOWN_ARRAY_TYPE;
type = (enum array_types)(type - 1)) {
if (strcmp(names[type], type_name) == 0)
break;
}
if (type == UNKNOWN_ARRAY_TYPE)
fprintf(stderr, "unknown type: %s\n", type_name);
return type;
}
/*
* find_aray -- return info about array with proper name
*/
static TOID(struct array_info)
find_array(const char *name)
{
TOID(struct array_info) info;
POBJ_FOREACH_TYPE(pop, info) {
if (strncmp(D_RO(info)->name, name, MAX_BUFFLEN) == 0)
return info;
}
return TOID_NULL(struct array_info);
}
/*
* elm_constructor -- constructor of array_elm type object
*/
static int
elm_constructor(PMEMobjpool *pop, void *ptr, void *arg)
{
struct array_elm *obj = (struct array_elm *)ptr;
int *id = (int *)arg;
obj->id = *id;
pmemobj_persist(pop, obj, sizeof(*obj));
return 0;
}
/*
* print_int -- print array of int type
*/
static void
print_int(struct array_info *info)
{
TOID(int) array;
TOID_ASSIGN(array, info->array);
for (size_t i = 0; i < info->size; i++)
printf("%d ", D_RO(array)[i]);
}
/*
* print_pmemoid -- print array of PMEMoid type
*/
static void
print_pmemoid(struct array_info *info)
{
TOID(PMEMoid) array;
TOID(struct array_elm) elm;
TOID_ASSIGN(array, info->array);
for (size_t i = 0; i < info->size; i++) {
TOID_ASSIGN(elm, D_RW(array)[i]);
printf("%d ", D_RO(elm)->id);
}
}
/*
* print_toid -- print array of TOID(struct array_elm) type
*/
static void
print_toid(struct array_info *info)
{
TOID_ARRAY(TOID(struct array_elm)) array;
TOID_ASSIGN(array, info->array);
for (size_t i = 0; i < info->size; i++)
printf("%d ", D_RO(D_RO(array)[i])->id);
}
typedef void (*fn_print)(struct array_info *info);
static fn_print print_array[] = {NULL, print_int, print_pmemoid, print_toid};
/*
* free_int -- de-allocate array of int type
*/
static void
free_int(struct array_info *info)
{
TOID(int) array;
TOID_ASSIGN(array, info->array);
/*
* When there is persistent array of simple type allocated,
* there is enough to de-allocate persistent pointer
*/
POBJ_FREE(&array);
}
/*
* free_pmemoid -- de-allocate array of PMEMoid type
*/
static void
free_pmemoid(struct array_info *info)
{
TOID(PMEMoid) array;
TOID_ASSIGN(array, info->array);
/*
* When there is persistent array of persistent pointer type allocated,
* there is necessary to de-allocate each element, if they were
* allocated earlier
*/
for (size_t i = 0; i < info->size; i++)
pmemobj_free(&D_RW(array)[i]);
POBJ_FREE(&array);
}
/*
* free_toid -- de-allocate array of TOID(struct array_elm) type
*/
static void
free_toid(struct array_info *info)
{
TOID_ARRAY(TOID(struct array_elm)) array;
TOID_ASSIGN(array, info->array);
/*
* When there is persistent array of persistent pointer type allocated,
* there is necessary to de-allocate each element, if they were
* allocated earlier
*/
for (size_t i = 0; i < info->size; i++)
POBJ_FREE(&D_RW(array)[i]);
POBJ_FREE(&array);
}
typedef void (*fn_free)(struct array_info *info);
static fn_free free_array[] = {NULL, free_int, free_pmemoid, free_toid};
/*
* realloc_int -- reallocate array of int type
*/
static PMEMoid
realloc_int(PMEMoid *info, size_t prev_size, size_t size)
{
TOID(int) array;
TOID_ASSIGN(array, *info);
POBJ_REALLOC(pop, &array, int, size * sizeof(int));
for (size_t i = prev_size; i < size; i++)
D_RW(array)[i] = (int)i;
return array.oid;
}
/*
* realloc_pmemoid -- reallocate array of PMEMoid type
*/
static PMEMoid
realloc_pmemoid(PMEMoid *info, size_t prev_size, size_t size)
{
TOID(PMEMoid) array;
TOID_ASSIGN(array, *info);
pmemobj_zrealloc(pop, &array.oid, sizeof(PMEMoid) * size,
TOID_TYPE_NUM(PMEMoid));
for (size_t i = prev_size; i < size; i++) {
if (pmemobj_alloc(pop, &D_RW(array)[i],
sizeof(struct array_elm), TOID_TYPE_NUM(PMEMoid),
elm_constructor, &i)) {
fprintf(stderr, "pmemobj_alloc\n");
assert(0);
}
}
return array.oid;
}
/*
* realloc_toid -- reallocate array of TOID(struct array_elm) type
*/
static PMEMoid
realloc_toid(PMEMoid *info, size_t prev_size, size_t size)
{
TOID_ARRAY(TOID(struct array_elm)) array;
TOID_ASSIGN(array, *info);
pmemobj_zrealloc(pop, &array.oid,
sizeof(TOID(struct array_elm)) * size,
TOID_TYPE_NUM_OF(array));
for (size_t i = prev_size; i < size; i++) {
POBJ_NEW(pop, &D_RW(array)[i], struct array_elm,
elm_constructor, &i);
if (TOID_IS_NULL(D_RW(array)[i])) {
fprintf(stderr, "POBJ_ALLOC\n");
assert(0);
}
}
return array.oid;
}
typedef PMEMoid (*fn_realloc)(PMEMoid *info, size_t prev_size, size_t size);
static fn_realloc realloc_array[] =
{NULL, realloc_int, realloc_pmemoid, realloc_toid};
/*
* alloc_int -- allocate array of int type
*/
static PMEMoid
alloc_int(size_t size)
{
TOID(int) array;
/*
* To allocate persistent array of simple type is enough to allocate
* pointer with size equal to number of elements multiplied by size of
* user-defined structure.
*/
POBJ_ALLOC(pop, &array, int, sizeof(int) * size,
NULL, NULL);
if (TOID_IS_NULL(array)) {
fprintf(stderr, "POBJ_ALLOC\n");
return OID_NULL;
}
for (size_t i = 0; i < size; i++)
D_RW(array)[i] = (int)i;
pmemobj_persist(pop, D_RW(array), size * sizeof(*D_RW(array)));
return array.oid;
}
/*
* alloc_pmemoid -- allocate array of PMEMoid type
*/
static PMEMoid
alloc_pmemoid(size_t size)
{
TOID(PMEMoid) array;
/*
* To allocate persistent array of PMEMoid type is necessary to allocate
* pointer with size equal to number of elements multiplied by size of
* PMEMoid and to allocate each of elements separately.
*/
POBJ_ALLOC(pop, &array, PMEMoid, sizeof(PMEMoid) * size,
NULL, NULL);
if (TOID_IS_NULL(array)) {
fprintf(stderr, "POBJ_ALLOC\n");
return OID_NULL;
}
for (size_t i = 0; i < size; i++) {
if (pmemobj_alloc(pop, &D_RW(array)[i],
sizeof(struct array_elm),
TOID_TYPE_NUM(PMEMoid), elm_constructor, &i)) {
fprintf(stderr, "pmemobj_alloc\n");
}
}
return array.oid;
}
/*
* alloc_toid -- allocate array of TOID(struct array_elm) type
*/
static PMEMoid
alloc_toid(size_t size)
{
TOID_ARRAY(TOID(struct array_elm)) array;
/*
* To allocate persistent array of TOID with user-defined structure type
* is necessary to allocate pointer with size equal to number of
* elements multiplied by size of TOID of proper type and to allocate
* each of elements separately.
*/
POBJ_ALLOC(pop, &array, TOID(struct array_elm),
sizeof(TOID(struct array_elm)) * size, NULL, NULL);
if (TOID_IS_NULL(array)) {
fprintf(stderr, "POBJ_ALLOC\n");
return OID_NULL;
}
for (size_t i = 0; i < size; i++) {
POBJ_NEW(pop, &D_RW(array)[i], struct array_elm,
elm_constructor, &i);
if (TOID_IS_NULL(D_RW(array)[i])) {
fprintf(stderr, "POBJ_ALLOC\n");
assert(0);
}
}
return array.oid;
}
typedef PMEMoid (*fn_alloc)(size_t size);
static fn_alloc alloc_array[] = {NULL, alloc_int, alloc_pmemoid, alloc_toid};
/*
* do_print -- print values stored by proper array
*/
static void
do_print(int argc, char *argv[])
{
if (argc != 1) {
printf("usage: ./array <file-name> print <array-name>\n");
return;
}
TOID(struct array_info) array_info = find_array(argv[0]);
if (TOID_IS_NULL(array_info)) {
printf("%s doesn't exist\n", argv[0]);
return;
}
printf("%s:\n", argv[0]);
print_array[D_RO(array_info)->type](D_RW(array_info));
printf("\n");
}
/*
* do_free -- de-allocate proper array and proper TOID of array_info type
*/
static void
do_free(int argc, char *argv[])
{
if (argc != 1) {
printf("usage: ./array <file-name> free <array-name>\n");
return;
}
TOID(struct array_info) array_info = find_array(argv[0]);
if (TOID_IS_NULL(array_info)) {
printf("%s doesn't exist\n", argv[0]);
return;
}
free_array[D_RO(array_info)->type](D_RW(array_info));
POBJ_FREE(&array_info);
}
/*
* do_realloc -- reallocate proper array to given size and update information
* in array_info structure
*/
static void
do_realloc(int argc, char *argv[])
{
if (argc != 2) {
printf("usage: ./array <file-name> realloc"
" <array-name> <size>\n");
return;
}
size_t size = atoi(argv[1]);
TOID(struct array_info) array_info = find_array(argv[0]);
if (TOID_IS_NULL(array_info)) {
printf("%s doesn't exist\n", argv[0]);
return;
}
struct array_info *info = D_RW(array_info);
info->array = realloc_array[info->type](&info->array, info->size, size);
if (OID_IS_NULL(info->array)) {
if (size != 0)
printf("POBJ_REALLOC\n");
}
info->size = size;
pmemobj_persist(pop, info, sizeof(*info));
}
/*
* do_alloc -- allocate persistent array and TOID of array_info type
* and set it with information about new array
*/
static void
do_alloc(int argc, char *argv[])
{
if (argc != 3) {
printf("usage: ./array <file-name> alloc <array-name>"
"<size> <type>\n");
return;
}
enum array_types type = get_type(argv[2]);
if (type == UNKNOWN_ARRAY_TYPE)
return;
size_t size = atoi(argv[1]);
TOID(struct array_info) array_info = find_array(argv[0]);
if (!TOID_IS_NULL(array_info))
POBJ_FREE(&array_info);
POBJ_ZNEW(pop, &array_info, struct array_info);
struct array_info *info = D_RW(array_info);
strncpy(info->name, argv[0], MAX_BUFFLEN);
info->name[MAX_BUFFLEN - 1] = '\0';
info->size = size;
info->type = type;
info->array = alloc_array[type](size);
if (OID_IS_NULL(info->array))
assert(0);
pmemobj_persist(pop, info, sizeof(*info));
}
typedef void (*fn_op)(int argc, char *argv[]);
static fn_op operations[] = {do_alloc, do_realloc, do_free, do_print};
int
main(int argc, char *argv[])
{
if (argc < 3) {
print_usage();
return 1;
}
const char *path = argv[1];
pop = NULL;
if (file_exists(path) != 0) {
if ((pop = pmemobj_create(path, POBJ_LAYOUT_NAME(array),
PMEMOBJ_MIN_POOL, CREATE_MODE_RW)) == NULL) {
printf("failed to create pool\n");
return 1;
}
} else {
if ((pop = pmemobj_open(path, POBJ_LAYOUT_NAME(array)))
== NULL) {
printf("failed to open pool\n");
return 1;
}
}
const char *option = argv[2];
argv += 3;
argc -= 3;
const char *names[] = {"alloc", "realloc", "free", "print"};
int i = 0;
for (; i < COUNT_OF(names) && strcmp(option, names[i]) != 0; i++);
if (i != COUNT_OF(names))
operations[i](argc, argv);
else
print_usage();
pmemobj_close(pop);
return 0;
}