59
how does the application find the data structures resident in that range? For persistent
memory, there must be at least one well-known location of a data structure to use as a
starting point. This is often referred to as a root object (described in Chapter 7). The root
object is used by many of the higher-level libraries within PMDK to access the data.
Flushing Is Not Transactional
It is important to separate the ideas of flushing to persistence from transactional
updates. Flushing changes to storage using calls like msync() or fsync() on Linux
and FlushFileBuffers() on Windows have never provided transactional updates.
Applications assume the responsibility for maintaining consistent storage data structures
in addition to flushing changes to storage. With persistent memory, the same is true. In
Chapter 3, a simple program stored a string to persistent memory and then flushed it to
make sure the change was persistent. But that code was not transactional, and in the face
of failure, the change could be in just about any state – from completely lost to partially
lost to fully completed.
A fundamental property of caches is that they hold data temporarily for
performance, but they do not typically hold data until a transaction is ready to commit.
Normal system activity can cause cache pressure and evict data at any time and in any
order. If the examples in Chapter 3 were interrupted by power failure, it is possible for
any part of the string being stored to be lost and any part to be persistent, in any order.
It is important to think of the cache flush operation as flush anything that hasn’t already
been flushed and not as flush all my changes now.
Finally, we showed a decision tree in Chapter 2 (Figure 2-5) where an application can
determine at startup that no cache flushing is required for persistent memory. This can
be the case on platforms where the CPU cache is flushed automatically on power failure,
for example. Even on platforms where flush instructions are not needed, transactions are
still required to keep data structures consistent in the face of failure.
Start-Time Responsibilities
In Chapter 2 (Figures 2-5 and 2-6), we showed flowcharts outlining the application’s
responsibilities when using persistent memory. These responsibilities included
detecting platform details, available instructions, media failures, and so on. For storage,
these types of things happen in the storage stack in the operating system. Persistent
Chapter 4 Fundamental ConCepts oF persistent memory programming
how does the application find the data structures resident in that range? For persistent
memory, there must be at least one well-known location of a data structure to use as a
starting point. This is often referred to as a root object (described in Chapter 7). The root
object is used by many of the higher-level libraries within PMDK to access the data.
Flushing Is Not Transactional
It is important to separate the ideas of flushing to persistence from transactional
updates. Flushing changes to storage using calls like msync() or fsync() on Linux
and FlushFileBuffers() on Windows have never provided transactional updates.
Applications assume the responsibility for maintaining consistent storage data structures
in addition to flushing changes to storage. With persistent memory, the same is true. In
Chapter 3, a simple program stored a string to persistent memory and then flushed it to
make sure the change was persistent. But that code was not transactional, and in the face
of failure, the change could be in just about any state – from completely lost to partially
lost to fully completed.
A fundamental property of caches is that they hold data temporarily for
performance, but they do not typically hold data until a transaction is ready to commit.
Normal system activity can cause cache pressure and evict data at any time and in any
order. If the examples in Chapter 3 were interrupted by power failure, it is possible for
any part of the string being stored to be lost and any part to be persistent, in any order.
It is important to think of the cache flush operation as flush anything that hasn’t already
been flushed and not as flush all my changes now.
Finally, we showed a decision tree in Chapter 2 (Figure 2-5) where an application can
determine at startup that no cache flushing is required for persistent memory. This can
be the case on platforms where the CPU cache is flushed automatically on power failure,
for example. Even on platforms where flush instructions are not needed, transactions are
still required to keep data structures consistent in the face of failure.
Start-Time Responsibilities
In Chapter 2 (Figures 2-5 and 2-6), we showed flowcharts outlining the application’s
responsibilities when using persistent memory. These responsibilities included
detecting platform details, available instructions, media failures, and so on. For storage,
these types of things happen in the storage stack in the operating system. Persistent
Chapter 4 Fundamental ConCepts oF persistent memory programming
