@@ -298,27 +298,34 @@ public abstract class AbstractFSWAL<W extends WriterBase> implements WAL {
298298 final Comparator <Path > LOG_NAME_COMPARATOR =
299299 (o1 , o2 ) -> Long .compare (getFileNumFromFileName (o1 ), getFileNumFromFileName (o2 ));
300300
301- private static final class WalProps {
301+ private static final class WALProps {
302302
303303 /**
304304 * Map the encoded region name to the highest sequence id.
305305 * <p/>
306306 * Contains all the regions it has an entry for.
307307 */
308- public final Map <byte [], Long > encodedName2HighestSequenceId ;
308+ final Map <byte [], Long > encodedName2HighestSequenceId ;
309309
310310 /**
311311 * The log file size. Notice that the size may not be accurate if we do asynchronous close in
312312 * sub classes.
313313 */
314- public final long logSize ;
314+ final long logSize ;
315315
316316 /**
317317 * The nanoTime of the log rolling, used to determine the time interval that has passed since.
318318 */
319- public final long rollTimeNs ;
319+ final long rollTimeNs ;
320320
321- public WalProps (Map <byte [], Long > encodedName2HighestSequenceId , long logSize ) {
321+ /**
322+ * If we do asynchronous close in sub classes, it is possible that when adding WALProps to the
323+ * rolled map, the file is not closed yet, so in cleanOldLogs we should not archive this file,
324+ * for safety.
325+ */
326+ volatile boolean closed = false ;
327+
328+ public WALProps (Map <byte [], Long > encodedName2HighestSequenceId , long logSize ) {
322329 this .encodedName2HighestSequenceId = encodedName2HighestSequenceId ;
323330 this .logSize = logSize ;
324331 this .rollTimeNs = System .nanoTime ();
@@ -329,7 +336,7 @@ public WalProps(Map<byte[], Long> encodedName2HighestSequenceId, long logSize) {
329336 * Map of WAL log file to properties. The map is sorted by the log file creation timestamp
330337 * (contained in the log file name).
331338 */
332- protected ConcurrentNavigableMap <Path , WalProps > walFile2Props =
339+ protected final ConcurrentNavigableMap <Path , WALProps > walFile2Props =
333340 new ConcurrentSkipListMap <>(LOG_NAME_COMPARATOR );
334341
335342 /**
@@ -348,6 +355,9 @@ public WalProps(Map<byte[], Long> encodedName2HighestSequenceId, long logSize) {
348355
349356 protected final AtomicBoolean rollRequested = new AtomicBoolean (false );
350357
358+ protected final ExecutorService closeExecutor = Executors .newCachedThreadPool (
359+ new ThreadFactoryBuilder ().setDaemon (true ).setNameFormat ("Close-WAL-Writer-%d" ).build ());
360+
351361 // Run in caller if we get reject execution exception, to avoid aborting region server when we get
352362 // reject execution exception. Usually this should not happen but let's make it more robust.
353363 private final ExecutorService logArchiveExecutor =
@@ -697,7 +707,7 @@ Map<byte[], List<byte[]>> findRegionsToForceFlush() throws IOException {
697707 Map <byte [], List <byte []>> regions = null ;
698708 int logCount = getNumRolledLogFiles ();
699709 if (logCount > this .maxLogs && logCount > 0 ) {
700- Map .Entry <Path , WalProps > firstWALEntry = this .walFile2Props .firstEntry ();
710+ Map .Entry <Path , WALProps > firstWALEntry = this .walFile2Props .firstEntry ();
701711 regions =
702712 this .sequenceIdAccounting .findLower (firstWALEntry .getValue ().encodedName2HighestSequenceId );
703713 }
@@ -720,17 +730,34 @@ Map<byte[], List<byte[]>> findRegionsToForceFlush() throws IOException {
720730 return regions ;
721731 }
722732
733+ /**
734+ * Mark this WAL file as closed and call cleanOldLogs to see if we can archive this file.
735+ */
736+ protected final void markClosedAndClean (Path path ) {
737+ WALProps props = walFile2Props .get (path );
738+ // typically this should not be null, but if there is no big issue if it is already null, so
739+ // let's make the code more robust
740+ if (props != null ) {
741+ props .closed = true ;
742+ cleanOldLogs ();
743+ }
744+ }
745+
723746 /**
724747 * Archive old logs. A WAL is eligible for archiving if all its WALEdits have been flushed.
725748 */
726- private void cleanOldLogs () throws IOException {
749+ private void cleanOldLogs () {
727750 List <Pair <Path , Long >> logsToArchive = null ;
728751 long now = System .nanoTime ();
729752 boolean mayLogTooOld = nextLogTooOldNs <= now ;
730753 ArrayList <byte []> regionsBlockingWal = null ;
731754 // For each log file, look at its Map of regions to highest sequence id; if all sequence ids
732755 // are older than what is currently in memory, the WAL can be GC'd.
733- for (Map .Entry <Path , WalProps > e : this .walFile2Props .entrySet ()) {
756+ for (Map .Entry <Path , WALProps > e : this .walFile2Props .entrySet ()) {
757+ if (!e .getValue ().closed ) {
758+ LOG .debug ("{} is not closed yet, will try archiving it next time" , e .getKey ());
759+ continue ;
760+ }
734761 Path log = e .getKey ();
735762 ArrayList <byte []> regionsBlockingThisWal = null ;
736763 long ageNs = now - e .getValue ().rollTimeNs ;
@@ -834,7 +861,7 @@ protected final void logRollAndSetupWalProps(Path oldPath, Path newPath, long ol
834861 String newPathString = newPath != null ? CommonFSUtils .getPath (newPath ) : null ;
835862 if (oldPath != null ) {
836863 this .walFile2Props .put (oldPath ,
837- new WalProps (this .sequenceIdAccounting .resetHighest (), oldFileLen ));
864+ new WALProps (this .sequenceIdAccounting .resetHighest (), oldFileLen ));
838865 this .totalLogSize .addAndGet (oldFileLen );
839866 LOG .info ("Rolled WAL {} with entries={}, filesize={}; new WAL {}" ,
840867 CommonFSUtils .getPath (oldPath ), oldNumEntries , StringUtils .byteDesc (oldFileLen ),
0 commit comments