Skip to content
This repository was archived by the owner on Apr 30, 2019. It is now read-only.

Commit 5058f08

Browse files
authored
Merge pull request #21 from kishorvpatil/yahooGcThreadFix17
YBK-156 - Lower memory usage in GarbageCollectionThread while extracting all ledger meta data
2 parents bd2ebcd + e259b56 commit 5058f08

File tree

2 files changed

+84
-11
lines changed

2 files changed

+84
-11
lines changed

bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/GarbageCollectorThread.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -378,16 +378,7 @@ private void doGcEntryLogs() {
378378
// Loop through all of the entry logs and remove the non-active ledgers.
379379
for (Long entryLogId : entryLogMetaMap.keySet()) {
380380
EntryLogMetadata meta = entryLogMetaMap.get(entryLogId);
381-
for (Long entryLogLedger : meta.getLedgersMap().keySet()) {
382-
// Remove the entry log ledger from the set if it isn't active.
383-
try {
384-
if (!ledgerStorage.ledgerExists(entryLogLedger)) {
385-
meta.removeLedger(entryLogLedger);
386-
}
387-
} catch (IOException e) {
388-
LOG.error("Error reading from ledger storage", e);
389-
}
390-
}
381+
removeIfLedgerNotExists(meta);
391382
if (meta.isEmpty()) {
392383
// This means the entry log is not associated with any active ledgers anymore.
393384
// We can remove this entry log file now.
@@ -397,6 +388,19 @@ private void doGcEntryLogs() {
397388
}
398389
}
399390

391+
private void removeIfLedgerNotExists(EntryLogMetadata meta) {
392+
for (Long entryLogLedger : meta.getLedgersMap().keySet()) {
393+
// Remove the entry log ledger from the set if it isn't active.
394+
try {
395+
if (!ledgerStorage.ledgerExists(entryLogLedger)) {
396+
meta.removeLedger(entryLogLedger);
397+
}
398+
} catch (IOException e) {
399+
LOG.error("Error reading from ledger storage", e);
400+
}
401+
}
402+
}
403+
400404
/**
401405
* Compact entry logs if necessary.
402406
*
@@ -549,7 +553,12 @@ protected Map<Long, EntryLogMetadata> extractMetaFromEntryLogs(Map<Long, EntryLo
549553
try {
550554
// Read through the entry log file and extract the entry log meta
551555
EntryLogMetadata entryLogMeta = entryLogger.getEntryLogMetadata(entryLogId);
552-
entryLogMetaMap.put(entryLogId, entryLogMeta);
556+
removeIfLedgerNotExists(entryLogMeta);
557+
if (entryLogMeta.isEmpty()) {
558+
entryLogger.removeEntryLog(entryLogId);
559+
} else {
560+
entryLogMetaMap.put(entryLogId, entryLogMeta);
561+
}
553562
} catch (IOException e) {
554563
hasExceptionWhenScan = true;
555564
LOG.warn("Premature exception when processing " + entryLogId +

bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionTest.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import java.io.File;
2424
import java.io.IOException;
2525
import java.nio.ByteBuffer;
26+
import java.util.HashMap;
27+
import java.util.Map;
2628
import java.util.Set;
2729
import java.util.concurrent.atomic.AtomicBoolean;
2830
import java.util.concurrent.atomic.AtomicInteger;
@@ -568,6 +570,68 @@ public void checkpointComplete(Checkpoint checkpoint,
568570
storage.gcThread.doCompactEntryLogs(threshold);
569571
}
570572

573+
/**
574+
* Test extractMetaFromEntryLogs optimized method to avoid excess memory usage.
575+
*/
576+
@Test(timeout = 60000)
577+
public void testExtractMetaFromEntryLogs() throws Exception {
578+
ServerConfiguration conf = TestBKConfiguration.newServerConfiguration();
579+
File tmpDir = createTempDir("bkTest", ".dir");
580+
File curDir = Bookie.getCurrentDirectory(tmpDir);
581+
Bookie.checkDirectoryStructure(curDir);
582+
conf.setLedgerDirNames(new String[] { tmpDir.toString() });
583+
584+
LedgerDirsManager dirs = new LedgerDirsManager(conf, conf.getLedgerDirs());
585+
final Set<Long> ledgers = Collections
586+
.newSetFromMap(new ConcurrentHashMap<Long, Boolean>());
587+
588+
LedgerManager manager = getLedgerManager(ledgers);
589+
590+
CheckpointSource checkpointSource = new CheckpointSource() {
591+
592+
@Override
593+
public Checkpoint newCheckpoint() {
594+
return null;
595+
}
596+
597+
@Override
598+
public void checkpointComplete(Checkpoint checkpoint,
599+
boolean compact) throws IOException {
600+
}
601+
};
602+
InterleavedLedgerStorage storage = new InterleavedLedgerStorage();
603+
storage.initialize(conf, manager, dirs, dirs, checkpointSource, NullStatsLogger.INSTANCE);
604+
final byte[] KEY = "foobar".getBytes();
605+
606+
for (long ledger = 0; ledger <= 10; ledger++) {
607+
ledgers.add(ledger);
608+
for(int entry = 1; entry <= 50; entry++) {
609+
try {
610+
storage.addEntry(genEntry(ledger, entry, ENTRY_SIZE));
611+
} catch (IOException e) {
612+
//ignore exception on failure to add entry.
613+
}
614+
};
615+
};
616+
617+
storage.flush();
618+
storage.shutdown();
619+
620+
storage = new InterleavedLedgerStorage();
621+
storage.initialize(conf, manager, dirs, dirs, checkpointSource, NullStatsLogger.INSTANCE);
622+
623+
long startingEntriesCount = storage.gcThread.entryLogger.getLeastUnflushedLogId() - storage.gcThread.scannedLogId;
624+
LOG.info("The old Log Entry count is: " + startingEntriesCount);
625+
626+
Map<Long, EntryLogMetadata> entryLogMetaData = new HashMap<>();
627+
Map<Long, EntryLogMetadata> finalEntryLogMetadataMap = storage.gcThread.extractMetaFromEntryLogs(entryLogMetaData);
628+
long finalEntriesCount = storage.gcThread.entryLogger.getLeastUnflushedLogId() - storage.gcThread.scannedLogId;
629+
LOG.info("The latest Log Entry count is: " + finalEntriesCount);
630+
631+
assertTrue("The GC did not clean up entries...", startingEntriesCount != finalEntriesCount);
632+
assertTrue("Entries Count is zero", finalEntriesCount == 0);
633+
}
634+
571635
private ByteBuffer genEntry(long ledger, long entry, int size) {
572636
ByteBuffer bb = ByteBuffer.wrap(new byte[size]);
573637
bb.putLong(ledger);

0 commit comments

Comments
 (0)