250
At first glance, the program appears correct. With every new iteration of the loop,
the counter is incremented, and then the array position is written and flushed. However,
pcounter is incremented before we write to the array, thus creating a discrepancy
between pcounter and the actual number of committed entries in the array. Although it
is true that pcounter is not flushed until after the loop, the program is only correct after
a crash if we assume that the changes to pcounter stay in the CPU caches (in that case, a
program crash in the middle of the loop would simply leave the counter to zero).
As mentioned at the beginning of this section, we cannot make that assumption. A
cache line can be evicted at any time. In the pseudocode example in Listing 12-37, we
could run into a bug where pcounter indicates that the array is longer than it really is,
making the reader() read uninitialized memory.
The code in Listings 12-38 and 12-39 provide a C++ implementation of the
pseudocode from Listing 12-37. Both use libpmemobj-cpp from the PMDK. Listing 12-38
is the writer program, and Listing 12-39 is the reader.
Listing 12-38. Example of writing to persistent memory with an out-of-order
write bug
33 #include
34 #include
35 #include
36 #include
37 #include
38 #include
39 #include
40 #include
41 #include
42 #include
43
44 using namespace std;
45 namespace pobj = pmem::obj;
46
47 struct header_t {
48
uint32_t counter;
49
uint8_t reserved[60];
50 };
Chapter 12 Debugging persistent MeMory appliCations
At first glance, the program appears correct. With every new iteration of the loop,
the counter is incremented, and then the array position is written and flushed. However,
pcounter is incremented before we write to the array, thus creating a discrepancy
between pcounter and the actual number of committed entries in the array. Although it
is true that pcounter is not flushed until after the loop, the program is only correct after
a crash if we assume that the changes to pcounter stay in the CPU caches (in that case, a
program crash in the middle of the loop would simply leave the counter to zero).
As mentioned at the beginning of this section, we cannot make that assumption. A
cache line can be evicted at any time. In the pseudocode example in Listing 12-37, we
could run into a bug where pcounter indicates that the array is longer than it really is,
making the reader() read uninitialized memory.
The code in Listings 12-38 and 12-39 provide a C++ implementation of the
pseudocode from Listing 12-37. Both use libpmemobj-cpp from the PMDK. Listing 12-38
is the writer program, and Listing 12-39 is the reader.
Listing 12-38. Example of writing to persistent memory with an out-of-order
write bug
33 #include
34 #include
35 #include
36 #include
37 #include
38 #include
39 #include
40 #include
41 #include
42 #include
43
44 using namespace std;
45 namespace pobj = pmem::obj;
46
47 struct header_t {
48
uint32_t counter;
49
uint8_t reserved[60];
50 };
Chapter 12 Debugging persistent MeMory appliCations
