Skip to content

Commit 4076ea8

Browse files
committed
Checkpoint cleaner work.
1 parent 0879989 commit 4076ea8

20 files changed

+387
-165
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Aravind Narayanan <[email protected]>
22
Diego Ongaro <[email protected]>
3+
John Ousterhout <[email protected]>
34
Stephen M. Rumble <[email protected]>
45
Ryan Stutsman <[email protected]>

src/BackupManager.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ class BackupManager {
147147
BackupManager(CoordinatorClient* coordinator,
148148
const Tub<uint64_t>& masterId,
149149
uint32_t replicas);
150-
BackupManager(BackupManager*);
150+
explicit BackupManager(BackupManager* prototype);
151151
~BackupManager();
152152

153153
void freeSegment(uint64_t segmentId);

src/InfRcTransport.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class InfRcTransport : public Transport {
7676
IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE);
7777
if (logMemoryRegion == NULL) {
7878
LOG(ERROR, "ibv_reg_mr failed to register %Zd bytes at %p",
79-
bytes, base);
79+
bytes, base);
8080
throw TransportException(HERE, "ibv_reg_mr failed");
8181
}
8282
logMemoryBase = reinterpret_cast<uintptr_t>(base);

src/Log.cc

+88-13
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "Log.h"
2121
#include "LogCleaner.h"
22+
#include "ShortMacros.h"
2223
#include "TransportManager.h" // for Log memory 0-copy registration hack
2324

2425
namespace RAMCloud {
@@ -153,7 +154,7 @@ Log::allocateHead()
153154

154155
digest.addSegment(newHeadId);
155156

156-
while(!freePendingDigestAndReferenceList.empty()) {
157+
while (!freePendingDigestAndReferenceList.empty()) {
157158
Segment& s = freePendingDigestAndReferenceList.front();
158159
freePendingDigestAndReferenceList.pop_front();
159160
freePendingReferenceList.push_back(s);
@@ -260,6 +261,7 @@ Log::append(LogEntryType type, const void *buffer, const uint64_t length,
260261
} while (seh == NULL);
261262

262263
stats.totalAppends++;
264+
stats.totalBytesAppended += seh->totalLength();
263265

264266
if (cleanerOption == INLINED_CLEANER)
265267
cleaner.clean();
@@ -278,8 +280,15 @@ Log::append(LogEntryType type, const void *buffer, const uint64_t length,
278280
void
279281
Log::free(LogEntryHandle entry)
280282
{
281-
getSegmentFromAddress(reinterpret_cast<const void*>(entry))->free(entry);
283+
Segment* s = getSegmentFromAddress(reinterpret_cast<const void*>(entry));
284+
285+
// This debug-only check should catch invalid free()s within legitimate
286+
// Segments.
287+
assert(entry->isChecksumValid());
288+
289+
s->free(entry);
282290
stats.totalFrees++;
291+
stats.totalBytesFreed += entry->totalLength();
283292
}
284293

285294
/**
@@ -347,7 +356,9 @@ Log::getCallbacks(LogEntryType type)
347356
return NULL;
348357
}
349358

350-
/// Wait for all segments to be fully replicated.
359+
/**
360+
* Wait for all segments to be fully replicated.
361+
*/
351362
void
352363
Log::sync()
353364
{
@@ -377,6 +388,10 @@ Log::getBytesAppended() const
377388
return stats.totalBytesAppended;
378389
}
379390

391+
/**
392+
* Return the total number of bytes freed in the Log. Like #getBytesAppended,
393+
* this number includes metadata overheads.
394+
*/
380395
uint64_t
381396
Log::getBytesFreed() const
382397
{
@@ -405,8 +420,16 @@ Log::getFromFreeList()
405420
return p;
406421
}
407422

423+
/**
424+
* Obtain a list of the Segments newly created since the last call to
425+
* this method. This is used by the cleaner to obtain candidate Segments
426+
* that have been closed and are eligible for cleaning at any time.
427+
*
428+
* \param[out] out
429+
* Vector of pointers with which to return the new cleanable Segments.
430+
*/
408431
void
409-
Log::getNewActiveSegments(SegmentVector& out)
432+
Log::getNewCleanableSegments(SegmentVector& out)
410433
{
411434
boost::lock_guard<SpinLock> lock(listLock);
412435

@@ -418,43 +441,64 @@ Log::getNewActiveSegments(SegmentVector& out)
418441
}
419442
}
420443

444+
/**
445+
* Alert the Log of a Segment that is about to contain live data. This
446+
* is used by the cleaner prior to relocating entries to new Segments.
447+
* The Log needs to be made aware of such Segments because it needs to
448+
* be able to handle #free calls on relocated objects, which can occur
449+
* immediately following the cleaner's relocation and before it completes
450+
* a cleaning pass.
451+
*
452+
* \param[in] segment
453+
* Pointer to the Segment that will shortly host live data.
454+
*/
421455
void
422456
Log::cleaningInto(Segment* segment)
423457
{
424458
boost::lock_guard<SpinLock> lock(listLock);
425459

426-
cleaningIntoList.push_back(*segment);
460+
cleaningIntoList.push_back(*segment);
427461
activeIdMap[segment->getId()] = segment;
428462
activeBaseAddressMap[segment->getBaseAddress()] = segment;
429463
}
430464

465+
/**
466+
* Alert the Log that the following Segments have been cleaned. The Log
467+
* takes note of the newly cleaned Segments and any new Segments reported
468+
* via the #cleaningInto method. When the next head is allocated in
469+
* #allocateHead, the LogDigest will be updated to reflect all of the new
470+
* Segments and none of the cleaned ones. This method also checks previously
471+
* cleaned Segments and any that have been removed from the Log and are no
472+
* longer be referenced by outstanding RPCs are returned to the free list.
473+
*
474+
* \param[in] clean
475+
* Vector of pointers to Segments that have been cleaned.
476+
*/
431477
void
432478
Log::cleaningComplete(SegmentVector& clean)
433479
{
434480
boost::lock_guard<SpinLock> lock(listLock);
435481

436-
// XXX- allocated Segments aren't on any list...
437-
// should we create a list for them just so they're
438-
// tracked?
482+
debugDumpLists();
439483

440484
while (!cleaningIntoList.empty()) {
441485
Segment& s = cleaningIntoList.front();
442486
cleaningIntoList.pop_front();
443487
cleanablePendingDigestList.push_back(s);
444488
}
445489

446-
foreach (Segment* s, clean) {
490+
foreach (Segment* s, clean) {
447491
cleanableList.erase(cleanableList.iterator_to(*s));
448492
freePendingDigestAndReferenceList.push_back(*s);
449493
}
450494

451495
// XXX- this is a good time to check the 'freePendingReferenceList'
452496
// and move any of those guys on to the freeList, if possible.
453497
foreach (Segment& s, freePendingReferenceList) {
454-
(void)s;
455-
456-
//activeIdMap.erase(s.getId());
457-
//activeBaseAddressMap.erase(s.getBaseAddress());
498+
if (0) {
499+
activeIdMap.erase(s.getId());
500+
activeBaseAddressMap.erase(s.getBaseAddress());
501+
}
458502
}
459503
}
460504

@@ -476,6 +520,37 @@ Log::allocateSegmentId()
476520
/// Private Methods
477521
////////////////////////////////////
478522

523+
/**
524+
* Print various Segment list counts to the debug log.
525+
*/
526+
void
527+
Log::debugDumpLists()
528+
{
529+
LOG(DEBUG, "============ LOG LIST OCCUPANCY ============");
530+
LOG(DEBUG, " freeList: %Zd", freeList.size());
531+
LOG(DEBUG, " cleanableNewList: %Zd",
532+
cleanableNewList.size());
533+
LOG(DEBUG, " cleanableList: %Zd",
534+
cleanableList.size());
535+
LOG(DEBUG, " cleaningIntoList: %Zd",
536+
cleaningIntoList.size());
537+
LOG(DEBUG, " cleanablePendingDigestList: %Zd",
538+
cleanablePendingDigestList.size());
539+
LOG(DEBUG, " freePendingDigestAndReferenceList: %Zd",
540+
freePendingDigestAndReferenceList.size());
541+
LOG(DEBUG, " freePendingReferenceList: %Zd",
542+
freePendingReferenceList.size());
543+
LOG(DEBUG, "----- Total: %Zd (Segments in Log (incl. head): %Zd)",
544+
freeList.size() +
545+
cleanableNewList.size() +
546+
cleanableList.size() +
547+
cleaningIntoList.size() +
548+
cleanablePendingDigestList.size() +
549+
freePendingDigestAndReferenceList.size() +
550+
freePendingReferenceList.size(),
551+
getNumberOfSegments());
552+
}
553+
479554
/**
480555
* Provide the Log with a single contiguous piece of backing Segment memory.
481556
* The memory provided must of at least as large as #segmentCapacity.

src/Log.h

+8-5
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class Log {
126126
size_t getNumberOfSegments() const;
127127

128128
// These public methods are only to be externally used by the cleaner.
129-
void getNewActiveSegments(SegmentVector& out);
129+
void getNewCleanableSegments(SegmentVector& out);
130130
void cleaningInto(Segment* newSegment);
131131
void cleaningComplete(SegmentVector &clean);
132132
void *getFromFreeList();
@@ -148,15 +148,17 @@ class Log {
148148
uint64_t totalBytesFreed;
149149
uint64_t totalFrees;
150150

151-
// permit direct twiddling of counters by authorised classes
152151
friend class Log;
153152
friend class LogTest;
154-
friend class Segment;
155153
};
156154

157155
LogStats stats;
158156

159157
PRIVATE:
158+
/**
159+
* Class used when destroying boost intrusive lists and destroying/freeing
160+
* all linked elements. See the intrusive list #clear_and_dispose method.
161+
*/
160162
class SegmentDisposer {
161163
public:
162164
void
@@ -173,6 +175,7 @@ class Log {
173175
typedef boost::unordered_map<uint64_t, Segment *> ActiveIdMap;
174176
typedef boost::unordered_map<const void *, Segment *> BaseAddressMap;
175177

178+
void debugDumpLists();
176179
void addSegmentMemory(void *p);
177180
void markActive(Segment *s);
178181
Segment* getSegmentFromAddress(const void*);
@@ -213,14 +216,14 @@ class Log {
213216
/// as well as Segments the LogCleaner has generated during cleaning).
214217
/// Every Segment on this list was previously on the #cleanableNewList.
215218
/// Segments transition to this list when the LogCleaner learns about
216-
/// them via the #getNewActiveSegments() method.
219+
/// them via the #getNewCleanableSegments() method.
217220
SegmentList cleanableList;
218221

219222
/// List of new Segments that the cleaner is currently cleaning to (placing
220223
/// live entries in). This is needed in case deletions of those entries
221224
/// occur before cleaning has finished (the Log code must be able to look
222225
/// up the Segment* from the pointer into the Segment to update the
223-
/// statistics). When #cleaningComplete() is called, this list is drained
226+
/// statistics). When #cleaningComplete() is called, this list is drained
224227
/// into the #cleanablePendingDigestList.
225228
SegmentList cleaningIntoList;
226229

0 commit comments

Comments
 (0)