323
in a transaction are different than redo logs because during the
commit’s fast path, they need to be invalidated instead of applied.
Instead of laboriously writing zeros into the log buffer, the log is
invalidated by incrementing the generation number. This works
because the number is part of the data with its checksum, so
changing the generation number will cause a checksum failure.
This algorithm allows libpmemobj to have only one additional
fence for the transaction (on top of the fences needed for
snapshots) to ensure fail-safety of a log, resulting in very lowoverhead transactions.
Persistent Allocations: The Interface
of a Transactional Persistent Allocator
The internal allocator interface in libpmemobj is far more complex than a typical volatile
dynamic memory allocator. First, it must ensure fail-safety of all its operations and
cannot allow for any memory to become unreachable due to interruptions. Second, it
must be transactional so that multiple operations on the heap can be done atomically
alongside other modifications. And lastly, it must operate on the pool state, allocating
memory from specific files instead of relying on the anonymous virtual memory
provided by the operating system. All these factors contribute to an internal API that
hardly resembles the standard malloc() and free(), shown in Listing 16-1.
Listing 16-1. The core persistent memory allocator interface that splits heap
operations into two distinct steps
int palloc_reserve(struct palloc_heap *heap, size_t size,...,
struct pobj_action *act);
void palloc_publish(struct palloc_heap *heap,
struct pobj_action *actv, size_t actvcnt,
struct operation_context *ctx);
Chapter 16 pMDK Internals: IMportant algorIthMs anD Data struCtures
Précédent

- 347/457

Suivant