Sync translog without lock when trim unreferenced readers (#46203)

With this change, we can avoid blocking writing threads when trimming
unreferenced readers; hence improving the translog writing performance
in async durability mode.

Close #46201
This commit is contained in:
dengweisysu 2019-09-03 02:56:22 +08:00 committed by Nhat Nguyen
parent e01ec802e7
commit 416419e4c9
1 changed files with 20 additions and 9 deletions

View File

@ -1678,6 +1678,7 @@ public class Translog extends AbstractIndexShardComponent implements IndexShardC
* required generation * required generation
*/ */
public void trimUnreferencedReaders() throws IOException { public void trimUnreferencedReaders() throws IOException {
List<TranslogReader> toDeleteReaderList = new ArrayList<>();
try (ReleasableLock ignored = writeLock.acquire()) { try (ReleasableLock ignored = writeLock.acquire()) {
if (closed.get()) { if (closed.get()) {
// we're shutdown potentially on some tragic event, don't delete anything // we're shutdown potentially on some tragic event, don't delete anything
@ -1691,22 +1692,14 @@ public class Translog extends AbstractIndexShardComponent implements IndexShardC
"deletion policy requires a minReferenceGen of [" + minReferencedGen + "] which is higher than the current generation [" "deletion policy requires a minReferenceGen of [" + minReferencedGen + "] which is higher than the current generation ["
+ currentFileGeneration() + "]"; + currentFileGeneration() + "]";
for (Iterator<TranslogReader> iterator = readers.iterator(); iterator.hasNext(); ) { for (Iterator<TranslogReader> iterator = readers.iterator(); iterator.hasNext(); ) {
TranslogReader reader = iterator.next(); TranslogReader reader = iterator.next();
if (reader.getGeneration() >= minReferencedGen) { if (reader.getGeneration() >= minReferencedGen) {
break; break;
} }
iterator.remove(); iterator.remove();
toDeleteReaderList.add(reader);
IOUtils.closeWhileHandlingException(reader); IOUtils.closeWhileHandlingException(reader);
final Path translogPath = reader.path();
logger.trace("delete translog file [{}], not referenced and not current anymore", translogPath);
// The checkpoint is used when opening the translog to know which files should be recovered from.
// We now update the checkpoint to ignore the file we are going to remove.
// Note that there is a provision in recoverFromFiles to allow for the case where we synced the checkpoint
// but crashed before we could delete the file.
current.sync();
deleteReaderFiles(reader);
} }
assert readers.isEmpty() == false || current.generation == minReferencedGen : assert readers.isEmpty() == false || current.generation == minReferencedGen :
"all readers were cleaned but the minReferenceGen [" + minReferencedGen + "] is not the current writer's gen [" + "all readers were cleaned but the minReferenceGen [" + minReferencedGen + "] is not the current writer's gen [" +
@ -1715,6 +1708,24 @@ public class Translog extends AbstractIndexShardComponent implements IndexShardC
closeOnTragicEvent(ex); closeOnTragicEvent(ex);
throw ex; throw ex;
} }
// Do sync outside the writeLock to avoid blocking all writing thread.
if (toDeleteReaderList.isEmpty() == false) {
try {
// The checkpoint is used when opening the translog to know which files should be recovered from.
// We now update the checkpoint to ignore the file we are going to remove.
// Note that there is a provision in recoverFromFiles to allow for the case where we synced the checkpoint
// but crashed before we could delete the file.
sync();
for (TranslogReader reader : toDeleteReaderList) {
final Path translogPath = reader.path();
logger.trace("delete translog file [{}], not referenced and not current anymore", translogPath);
deleteReaderFiles(reader);
}
} catch (final Exception ex) {
closeOnTragicEvent(ex);
throw ex;
}
}
} }
/** /**