/* * 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(); }
/* * 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; }
/* * 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; }
/* * pocli_free -- free main context */ static void pocli_free(struct pocli *pcli) { while (pmemobj_tx_stage() != TX_STAGE_NONE) { while (pmemobj_tx_stage() != TX_STAGE_NONE) pmemobj_tx_process(); pmemobj_tx_end(); } pmemobj_close(pcli->ctx.pop); free(pcli->inbuf); free(pcli); }
/* * pocli_pmemobj_tx_end -- pmemobj_tx_end() command */ static enum pocli_ret pocli_pmemobj_tx_end(struct pocli_ctx *ctx, struct pocli_args *args) { if (args->argc != 1) return POCLI_ERR_ARGS; if (pmemobj_tx_stage() == TX_STAGE_NONE || pmemobj_tx_stage() == TX_STAGE_WORK) return pocli_err(ctx, POCLI_ERR_ARGS, "transaction in improper stage\n"); ctx->tx_aborted = false; int ret = pmemobj_tx_end(); pocli_printf(ctx, "%s: %d\n", args->argv[0], ret); return POCLI_RET_OK; }
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); }