UMEM redo and undo

These are currently defined memory operations for redo and undo, it is quite different with what PMDK provided. Because WAL size is going to be critical, instead of coping all data bytes into WAL, umem defines different operations like MOVE and SET to describe memory operation behavior, instead of save its actual content. For example, MOVE is defined for memmove(), data content is already in-place before the move, there is no necessity to copy the data into WAL.

/* Type of memory actions */ enum { UMEM_ACT_NOOP = 0, /** copy appended payload to specified storage address */ UMEM_ACT_COPY, /** copy payload addressed by @ptr to specified storage address */ UMEM_ACT_COPY_PTR, /** assign 8/16/32/64 bits integer to specified storage address */ UMEM_ACT_ASSIGN, /** move specified bytes from source address to destination address */ UMEM_ACT_MOVE, /** memset a region with specified value */ UMEM_ACT_SET, /** set the specified bit in bitmap */ UMEM_ACT_SET_BITS, /** unset the specified bit in bitmap */ UMEM_ACT_CLR_BITS, /** it's checksum of the specified address */ UMEM_ACT_CSUM, };

Each umem_action can describe a memory operation and its parameters, some simple operations, e.g., set/clear bitmap and integer assignment, can fit into 16 bytes, other operations requires at least 32 bytes to describe the behavior and parameters.

/** * Memory operations for redo/undo. * 16 bytes for bit operation (set/clr) and integer assignment, 32+ bytes for * other operations. */ struct umem_action { uint16_t ac_opc; union { struct { uint64_t addr; uint64_t size; uint8_t payload[0]; } ac_copy; /**< copy payload from @payload to @addr */ struct { uint64_t addr; uint64_t size; uint64_t ptr; } ac_copy_ptr; /**< copy payload from @ptr to @addr */ struct { uint16_t size; uint32_t val; uint64_t addr; } ac_assign; /**< assign integer to @addr, int64 should use ac_copy */ struct { uint16_t num; uint32_t pos; uint64_t bmap; } ac_op_bits; /**< set or clear the @pos bit in bitmap @bmap */ struct { uint16_t val; uint32_t size; uint64_t addr; } ac_set; /**< memset(addr, val, size) */ struct { uint16_t pad16; uint32_t size; uint64_t src; uint64_t dst; } ac_move; /**< memmove(dst, size src) */ struct { uint16_t csum_sz; uint32_t size; uint64_t addr; uint8_t csum[0]; } ac_csum; /**< it is checksum of data stored in @addr */ }; };