Beispiel #1
0
/*
 * pmemlog_rewind -- discard all data, resetting a log memory pool to empty
 */
void
pmemlog_rewind(PMEMlogpool *plp)
{
	PMEMobjpool *pop = (PMEMobjpool *)plp;
	PMEMoid baseoid = pmemobj_root(pop, sizeof (struct base));
	struct base *bp = pmemobj_direct(baseoid);

	/* set the return point */
	jmp_buf env;
	if (setjmp(env)) {
		/* end the transaction */
		pmemobj_tx_end();
		return;
	}

	/* begin a transaction, also acquiring the write lock for the log */
	pmemobj_tx_begin(pop, env, TX_LOCK_RWLOCK, &bp->rwlock, TX_LOCK_NONE);
	/* add the root object to the undo log */
	pmemobj_tx_add_range(baseoid, 0, sizeof (struct base));

	/* free all log nodes */
	while (bp->head.off != 0) {
		PMEMoid nextoid =
			((struct log *)pmemobj_direct(bp->head))->hdr.next;
		pmemobj_tx_free(bp->head);
		bp->head = nextoid;
	}

	bp->head = OID_NULL;
	bp->tail = OID_NULL;
	bp->bytes_written = 0;

	pmemobj_tx_commit();
	pmemobj_tx_end();
}
Beispiel #2
0
/*
 * pocli_pmemobj_tx_begin -- pmemobj_tx_begin() command
 */
static enum pocli_ret
pocli_pmemobj_tx_begin(struct pocli_ctx *ctx, struct pocli_args *args)
{
	enum pocli_ret ret = POCLI_RET_OK;
	int r;
	switch (args->argc) {
		case 1: {
			r = pmemobj_tx_begin(ctx->pop, NULL, TX_PARAM_NONE);
			if (r != POCLI_RET_OK)
				return pocli_err(ctx, POCLI_ERR_ARGS,
					"pmemobj_tx_begin() failed");
			pocli_printf(ctx, "%s: %d\n", args->argv[0], r);
		}
		break;
		case 2: {
			if (strcmp(args->argv[1], "jmp") != 0)
				return POCLI_ERR_ARGS;
			jmp_buf jmp;
			if (setjmp(jmp)) {
				const char *command = ctx->tx_aborted ?
					"pmemobj_tx_abort" : "pmemobj_tx_end";
				pocli_printf(ctx, "%s: %d\n",
					command, pmemobj_tx_errno());
				return POCLI_RET_OK;
			} else {
				r = pmemobj_tx_begin(ctx->pop, jmp,
							TX_PARAM_NONE);
				if (r != POCLI_RET_OK)
					return pocli_err(ctx, POCLI_ERR_ARGS,
						"pmemobj_tx_begin() failed");
			}
			pocli_printf(ctx, "%s(jmp): %d\n", args->argv[0], r);
			ret = (enum pocli_ret)pocli_process(ctx->pocli);
			if (ret)
				return ret;

		}
		break;
		default:
			return POCLI_ERR_ARGS;
	}
	return ret;
}
Beispiel #3
0
/*
 * pmemlog_appendv -- add gathered data to a log memory pool
 */
int
pmemlog_appendv(PMEMlogpool *plp, const struct iovec *iov, int iovcnt)
{
	PMEMobjpool *pop = (PMEMobjpool *)plp;
	PMEMoid baseoid = pmemobj_root(pop, sizeof (struct base));
	struct base *bp = pmemobj_direct(baseoid);

	/* set the return point */
	jmp_buf env;
	if (setjmp(env)) {
		/* end the transaction */
		pmemobj_tx_end();
		return 1;
	}

	/* begin a transaction, also acquiring the write lock for the log */
	pmemobj_tx_begin(pop, env, TX_LOCK_RWLOCK, &bp->rwlock, TX_LOCK_NONE);

	/* add the base object to the undo log - once for the transaction */
	pmemobj_tx_add_range(baseoid, 0, sizeof (struct base));
	/* add the tail entry once to the undo log, if it is set */
	if (!OID_IS_NULL(bp->tail))
		pmemobj_tx_add_range(bp->tail, 0, sizeof (struct log));

	/* append the data */
	for (int i = 0; i < iovcnt; ++i) {
		char *buf = iov[i].iov_base;
		size_t count = iov[i].iov_len;

		/* allocate the new node to be inserted */
		PMEMoid log = pmemobj_tx_alloc(count + sizeof (struct log_hdr),
				LOG_TYPE);

		struct log *logp = pmemobj_direct(log);
		logp->hdr.size = count;
		memcpy(logp->data, buf, count);
		logp->hdr.next = OID_NULL;

		if (bp->tail.off == 0) {
			bp->head = log;	/* update head */
		} else {
			((struct log *)pmemobj_direct(bp->tail))->hdr.next =
							log;
		}

		bp->tail = log; /* update tail */
		bp->bytes_written += count;
	}

	pmemobj_tx_commit();
	pmemobj_tx_end();
	return 0;
}
Beispiel #4
0
/*
 * pmemlog_append -- add data to a log memory pool
 */
int
pmemlog_append(PMEMlogpool *plp, const void *buf, size_t count)
{
	PMEMobjpool *pop = (PMEMobjpool *)plp;
	PMEMoid baseoid = pmemobj_root(pop, sizeof (struct base));
	struct base *bp = pmemobj_direct(baseoid);

	/* set the return point */
	jmp_buf env;
	if (setjmp(env)) {
		/* end the transaction */
		pmemobj_tx_end();
		return 1;
	}

	/* begin a transaction, also acquiring the write lock for the log */
	pmemobj_tx_begin(pop, env, TX_LOCK_RWLOCK, &bp->rwlock, TX_LOCK_NONE);

	/* allocate the new node to be inserted */
	PMEMoid log = pmemobj_tx_alloc(count + sizeof (struct log_hdr),
				LOG_TYPE);

	struct log *logp = pmemobj_direct(log);
	logp->hdr.size = count;
	memcpy(logp->data, buf, count);
	logp->hdr.next = OID_NULL;

	/* add the modified root object to the undo log */
	pmemobj_tx_add_range(baseoid, 0, sizeof (struct base));
	if (bp->tail.off == 0) {
		/* update head */
		bp->head = log;
	} else {
		/* add the modified tail entry to the undo log */
		pmemobj_tx_add_range(bp->tail, 0, sizeof (struct log));
		((struct log *)pmemobj_direct(bp->tail))->hdr.next = log;
	}

	bp->tail = log; /* update tail */
	bp->bytes_written += count;

	pmemobj_tx_commit();
	pmemobj_tx_end();
	return 0;
}
Beispiel #5
0
int
main(int argc, char *argv[])
{
	START(argc, argv, "obj_tx_flow");

	if (argc != 2)
		FATAL("usage: %s [file]", argv[0]);

	PMEMobjpool *pop;
	if ((pop = pmemobj_create(argv[1], LAYOUT_NAME, PMEMOBJ_MIN_POOL,
	    S_IWUSR | S_IRUSR)) == NULL)
		FATAL("!pmemobj_create");

	int a = 0;
	int b = 0;
	int c = 0;

	TX_BEGIN(pop) {
		a = TEST_VALUE_A;
	} TX_ONCOMMIT {
		ASSERT(a == TEST_VALUE_A);
		b = TEST_VALUE_B;
	} TX_ONABORT { /* not called */
		a = TEST_VALUE_B;
	} TX_FINALLY {
		ASSERT(b == TEST_VALUE_B);
		c = TEST_VALUE_C;
	} TX_END

	ASSERT(a == TEST_VALUE_A);
	ASSERT(b == TEST_VALUE_B);
	ASSERT(c == TEST_VALUE_C);

	a = 0;
	b = 0;
	c = 0;

	TX_BEGIN(pop) {
		a = TEST_VALUE_A;
		pmemobj_tx_abort(EINVAL);
		a = TEST_VALUE_B;
	} TX_ONCOMMIT { /* not called */
		a = TEST_VALUE_B;
	} TX_ONABORT {
		ASSERT(a == TEST_VALUE_A);
		b = TEST_VALUE_B;
	} TX_FINALLY {
		ASSERT(b == TEST_VALUE_B);
		c = TEST_VALUE_C;
	} TX_END

	ASSERT(a == TEST_VALUE_A);
	ASSERT(b == TEST_VALUE_B);
	ASSERT(c == TEST_VALUE_C);

	a = 0;
	b = 0;
	c = 0;

	TX_BEGIN(pop) {
		TX_BEGIN(pop) {
			a = TEST_VALUE_A;
		} TX_ONCOMMIT {
			ASSERT(a == TEST_VALUE_A);
			b = TEST_VALUE_B;
		} TX_END
	} TX_ONCOMMIT {
		c = TEST_VALUE_C;
	} TX_END

	ASSERT(a == TEST_VALUE_A);
	ASSERT(b == TEST_VALUE_B);
	ASSERT(c == TEST_VALUE_C);

	a = 0;
	b = 0;
	c = 0;

	TX_BEGIN(pop) {
		a = TEST_VALUE_C;
		TX_BEGIN(pop) {
			a = TEST_VALUE_A;
			pmemobj_tx_abort(EINVAL);
			a = TEST_VALUE_B;
		} TX_ONCOMMIT { /* not called */
			a = TEST_VALUE_C;
		} TX_ONABORT {
			ASSERT(a == TEST_VALUE_A);
			b = TEST_VALUE_B;
		} TX_FINALLY {
			ASSERT(b == TEST_VALUE_B);
			c = TEST_VALUE_C;
		} TX_END
		a = TEST_VALUE_B;
	} TX_ONCOMMIT { /* not called */
		ASSERT(a == TEST_VALUE_A);
		c = TEST_VALUE_C;
	} TX_ONABORT {
		ASSERT(a == TEST_VALUE_A);
		ASSERT(b == TEST_VALUE_B);
		ASSERT(c == TEST_VALUE_C);
		a = TEST_VALUE_B;
	} TX_FINALLY {
		ASSERT(a == TEST_VALUE_B);
		b = TEST_VALUE_A;
	} TX_END

	ASSERT(a == TEST_VALUE_B);
	ASSERT(b == TEST_VALUE_A);
	ASSERT(c == TEST_VALUE_C);

	a = 0;
	b = 0;
	c = 0;

	pmemobj_tx_begin(pop, NULL, TX_LOCK_NONE);
	pmemobj_tx_abort(EINVAL);
	ASSERT(pmemobj_tx_stage() == TX_STAGE_ONABORT);
	a = TEST_VALUE_A;
	pmemobj_tx_end();

	ASSERT(a == TEST_VALUE_A);

	pmemobj_close(pop);

	DONE(NULL);
}