[ 
https://issues.apache.org/jira/browse/BOOKKEEPER-926?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15266884#comment-15266884
 ] 

Venkateswararao Jujjuri (JV) commented on BOOKKEEPER-926:
---------------------------------------------------------

[~rithin.shetty] and I noticed this at Salesforce testing.

Our stack looked like this:

"GarbageCollectorThread" prio=10 tid=0x00007f6981152330 nid=0x13da5 in 
Object.wait() [0x00007f68cc5d9000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at 
org.apache.bookkeeper.bookie.GarbageCollectorThread$CompactionScannerFactory.waitEntrylogFlushed(GarbageCollectorThread.java:182)
        - locked <0x0000000480b13168> (a java.lang.Object)
        - locked <0x0000000480b01a38> (a 
org.apache.bookkeeper.bookie.GarbageCollectorThread$CompactionScannerFactory)
        at 
org.apache.bookkeeper.bookie.GarbageCollectorThread$CompactionScannerFactory.flush(GarbageCollectorThread.java:201)
        - locked <0x0000000480b01a38> (a 
org.apache.bookkeeper.bookie.GarbageCollectorThread$CompactionScannerFactory)
        at 
org.apache.bookkeeper.bookie.GarbageCollectorThread.doCompactEntryLogs(GarbageCollectorThread.java:488)
        at 
org.apache.bookkeeper.bookie.GarbageCollectorThread.run(GarbageCollectorThread.java:388)

Also when [~rithin.shetty] added debug in the while loop mentioned above:

[vagrant@gus-mnds7-1-sfm sfslogs]$ grep "GC thread stuck" 
bookkeeper-bookie-gus-mnds7-1-sfm.gus.2015105437.vpod.sfdc.net.log
2016-05-01 19:59:21,271 - INFO 
[GarbageCollectorThread:GarbageCollectorThread$CompactionScannerFactory@187] - 
GC thread stuck waiting: lastOffsetLogId=12234, leastUnflushedLogId=12247
2016-05-01 20:14:21,886 - INFO 
[GarbageCollectorThread:GarbageCollectorThread$CompactionScannerFactory@187] - 
GC thread stuck waiting: lastOffsetLogId=12234, leastUnflushedLogId=12268
2016-05-01 20:29:22,181 - INFO 
[GarbageCollectorThread:GarbageCollectorThread$CompactionScannerFactory@187] - 
GC thread stuck waiting: lastOffsetLogId=12234, leastUnflushedLogId=12284
2016-05-01 20:44:22,940 - INFO 
[GarbageCollectorThread:GarbageCollectorThread$CompactionScannerFactory@187] - 
GC thread stuck waiting: lastOffsetLogId=12234, leastUnflushedLogId=12291
2016-05-01 20:59:28,856 - INFO 
[GarbageCollectorThread:GarbageCollectorThread$CompactionScannerFactory@187] - 
GC thread stuck waiting: lastOffsetLogId=12234, leastUnflushedLogId=12305

----
As you can see lastUnflushedLogId is growing pretty fast. [~merlimat] What I 
see is, leastUnflushedLogId keeps getting updated even after flush started and 
hence a problem too?

> Compacted entries are not properly synced before updating index
> ---------------------------------------------------------------
>
>                 Key: BOOKKEEPER-926
>                 URL: https://issues.apache.org/jira/browse/BOOKKEEPER-926
>             Project: Bookkeeper
>          Issue Type: Bug
>    Affects Versions: 4.3.1
>            Reporter: Matteo Merli
>            Assignee: Matteo Merli
>             Fix For: 4.4.0
>
>
> I have identified a couple of issues in Bookie compaction code. 
> h4. Compacted entries are not properly synced when index is updated
> When compacting, we read "active" entries from an entry log and we re-append 
> to current entry log. After compacting a number of entries, by default 100K, 
> or at the very end, we need to update the index pointing to the new entry log 
> and offset.
> Before updating the index, we need to wait for this entries to be flushed and 
> fsynced, otherwise a bookie crash might leave the index updated, pointing to 
> an invalid offset.
> The current code that is supposed to wait until flushed is:
> {code:java}
> // GarbageCollectorThread.java:178
> EntryLocation lastOffset = offsets.get(offsets.size()-1);
> long lastOffsetLogId = EntryLogger.logIdForOffset(lastOffset.location);
> while (lastOffsetLogId < entryLogger.getLeastUnflushedLogId() && running) {
>     synchronized (flushLock) {
>         flushLock.wait(1000);
>     }
>     lastOffset = offsets.get(offsets.size()-1);
>     lastOffsetLogId = EntryLogger.logIdForOffset(lastOffset.location);
> }
> // update the index 
> {code}
> The condition {{lastOffsetLogId < entryLogger.getLeastUnflushedLogId()}} is 
> wrong, because if the last compacted entry was written in an earlier entry 
> log than the least unflushed log, it means that the entries are already 
> flushed and thus we don't need to wait.
> In the normal case what happens is that {{lastOffsetLogId} is actually the 
> current entryLog and it's equal to {{entryLogger.getLeastUnflushedLogId()}}, 
> so we don't wait. But, in this case the entries appended to the current 
> entrylog are not flushed nor synced, hence the problem. 
> h4. Exception during index flush
> Having an exception when updating the index, combined with the above issue, 
> makes the bookie GC to stop indefinitely. 
> What happens is that the offset list is not cleared, and at the next bookie 
> GC iteration it will find the old compacted entries in that list, for which 
> now the entryLogId is less than the current log id, and that makes the while 
> loop to never exit.
> Another problem is that, any IOException during the index flush, will make 
> the GC thread to bail out and it will not remove even the entry logs that 
> were compacted and flushed. Next time, these entry logs will be compacted 
> again.
> h4. Proposed solution
> I think the best solution is to trigger the {{entryLogger.flush()}} form the 
> bookie GC thread before updating the indexes. That would simplify the code 
> and I don't see any disadvantages in doing that. 
> Another improvement would be to delete compacted entry logs individually, as 
> soon as the compacted data is flush, without waiting the end of the whole 
> compaction process. 
> The advantages are : 
>  * If compaction stop halfway, at least we don't have to re-compact what we 
> just compacted
>  * Compaction won't require significant space overhead. Today a major 
> compaction can end up reappending a large amount of data and then deleting 
> all the entry logs at the very end, requiring twice the size of the active 
> data set to be stored on disk at some point in time.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to