19
19
20
20
#include " Log.h"
21
21
#include " LogCleaner.h"
22
+ #include " ShortMacros.h"
22
23
#include " TransportManager.h" // for Log memory 0-copy registration hack
23
24
24
25
namespace RAMCloud {
@@ -153,7 +154,7 @@ Log::allocateHead()
153
154
154
155
digest.addSegment (newHeadId);
155
156
156
- while (!freePendingDigestAndReferenceList.empty ()) {
157
+ while (!freePendingDigestAndReferenceList.empty ()) {
157
158
Segment& s = freePendingDigestAndReferenceList.front ();
158
159
freePendingDigestAndReferenceList.pop_front ();
159
160
freePendingReferenceList.push_back (s);
@@ -260,6 +261,7 @@ Log::append(LogEntryType type, const void *buffer, const uint64_t length,
260
261
} while (seh == NULL );
261
262
262
263
stats.totalAppends ++;
264
+ stats.totalBytesAppended += seh->totalLength ();
263
265
264
266
if (cleanerOption == INLINED_CLEANER)
265
267
cleaner.clean ();
@@ -278,8 +280,15 @@ Log::append(LogEntryType type, const void *buffer, const uint64_t length,
278
280
void
279
281
Log::free (LogEntryHandle entry)
280
282
{
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);
282
290
stats.totalFrees ++;
291
+ stats.totalBytesFreed += entry->totalLength ();
283
292
}
284
293
285
294
/* *
@@ -347,7 +356,9 @@ Log::getCallbacks(LogEntryType type)
347
356
return NULL ;
348
357
}
349
358
350
- // / Wait for all segments to be fully replicated.
359
+ /* *
360
+ * Wait for all segments to be fully replicated.
361
+ */
351
362
void
352
363
Log::sync ()
353
364
{
@@ -377,6 +388,10 @@ Log::getBytesAppended() const
377
388
return stats.totalBytesAppended ;
378
389
}
379
390
391
+ /* *
392
+ * Return the total number of bytes freed in the Log. Like #getBytesAppended,
393
+ * this number includes metadata overheads.
394
+ */
380
395
uint64_t
381
396
Log::getBytesFreed () const
382
397
{
@@ -405,8 +420,16 @@ Log::getFromFreeList()
405
420
return p;
406
421
}
407
422
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
+ */
408
431
void
409
- Log::getNewActiveSegments (SegmentVector& out)
432
+ Log::getNewCleanableSegments (SegmentVector& out)
410
433
{
411
434
boost::lock_guard<SpinLock> lock (listLock);
412
435
@@ -418,43 +441,64 @@ Log::getNewActiveSegments(SegmentVector& out)
418
441
}
419
442
}
420
443
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
+ */
421
455
void
422
456
Log::cleaningInto (Segment* segment)
423
457
{
424
458
boost::lock_guard<SpinLock> lock (listLock);
425
459
426
- cleaningIntoList.push_back (*segment);
460
+ cleaningIntoList.push_back (*segment);
427
461
activeIdMap[segment->getId ()] = segment;
428
462
activeBaseAddressMap[segment->getBaseAddress ()] = segment;
429
463
}
430
464
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
+ */
431
477
void
432
478
Log::cleaningComplete (SegmentVector& clean)
433
479
{
434
480
boost::lock_guard<SpinLock> lock (listLock);
435
481
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 ();
439
483
440
484
while (!cleaningIntoList.empty ()) {
441
485
Segment& s = cleaningIntoList.front ();
442
486
cleaningIntoList.pop_front ();
443
487
cleanablePendingDigestList.push_back (s);
444
488
}
445
489
446
- foreach (Segment* s, clean) {
490
+ foreach (Segment* s, clean) {
447
491
cleanableList.erase (cleanableList.iterator_to (*s));
448
492
freePendingDigestAndReferenceList.push_back (*s);
449
493
}
450
494
451
495
// XXX- this is a good time to check the 'freePendingReferenceList'
452
496
// and move any of those guys on to the freeList, if possible.
453
497
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
+ }
458
502
}
459
503
}
460
504
@@ -476,6 +520,37 @@ Log::allocateSegmentId()
476
520
// / Private Methods
477
521
// //////////////////////////////////
478
522
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
+
479
554
/* *
480
555
* Provide the Log with a single contiguous piece of backing Segment memory.
481
556
* The memory provided must of at least as large as #segmentCapacity.
0 commit comments