-
Notifications
You must be signed in to change notification settings - Fork 517
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HDDS-11714. resetDeletedBlockRetryCount with --all may fail and can cause long db lock in large cluster #7665
base: master
Are you sure you want to change the base?
Conversation
@Override | ||
public List<DeletedBlocksTransaction> getFailedTransactionsBatch( | ||
int batchSize, long startTxId) throws IOException { | ||
List<DeletedBlocksTransaction> failedTXs = new ArrayList<>(); | ||
|
||
lock.lock(); | ||
try { | ||
try ( | ||
TableIterator<Long, ? extends Table.KeyValue<Long, DeletedBlocksTransaction>> iter = | ||
deletedBlockLogStateManager.getReadOnlyIterator()) { | ||
|
||
iter.seek(startTxId); | ||
|
||
while (iter.hasNext() && failedTXs.size() < batchSize) { | ||
DeletedBlocksTransaction delTX = iter.next().getValue(); | ||
if (delTX.getCount() == -1) { | ||
failedTXs.add(delTX); | ||
} | ||
} | ||
} | ||
} finally { | ||
lock.unlock(); | ||
} | ||
|
||
return failedTXs; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this additional method? The same thing can be achieved with the existing getFailedTransactions
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
} while (!batch.isEmpty()); | ||
} else { | ||
// Process txIDs provided by the user in batches |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user provided list of txIDs
reaches SCM via RPC call, so it's ok to process this in single go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
…ause long db lock in large cluster
e2df43e
to
88722d6
Compare
AUDIT.logReadFailure( | ||
buildAuditMessageForFailure( | ||
SCMAction.GET_FAILED_DELETED_BLOCKS_TRANSACTION, auditMap, ex) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid unnecessary formatting.
// These blocks cannot be found in the container, skip deleting them | ||
// eventually these TX will success. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid unnecessary formatting.
@@ -129,7 +129,7 @@ public List<DeletedBlocksTransaction> getFailedTransactions(int count, | |||
final List<DeletedBlocksTransaction> failedTXs = Lists.newArrayList(); | |||
try (TableIterator<Long, | |||
? extends Table.KeyValue<Long, DeletedBlocksTransaction>> iter = | |||
deletedBlockLogStateManager.getReadOnlyIterator()) { | |||
deletedBlockLogStateManager.getReadOnlyIterator()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid unnecessary formatting.
@@ -176,18 +176,52 @@ public void incrementCount(List<Long> txIDs) | |||
*/ | |||
@Override | |||
public int resetCount(List<Long> txIDs) throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can simplify the whole logic
public int resetCount(List<Long> txIDs) throws IOException {
if (txIDs != null) {
try {
lock.lock();
transactionStatusManager.resetRetryCount(txIDs);
return deletedBlockLogStateManager.resetRetryCountOfTransactionInDB(
new ArrayList<>(txIDs));
} finally {
lock.unlock();
} catch (Exception e) {
throw new IOException("Error during transaction reset", e);
}
}
final int batchSize = 1000;
int totalProcessed = 0;
long startTxId = 0;
try {
// If txIDs are not provided, fetch all failed transactions in batches
List<DeletedBlocksTransaction> batch;
do {
// Fetch the batch of failed transactions
batch = getFailedTransactions(batchSize, startTxId);
List<Long> batchTxIDs = batch.stream().map(DeletedBlocksTransaction::getTxID).collect(Collectors.toList());
totalProcessed += resetCount(batchTxIDs);
// Update startTxId to continue from the last processed transaction in the next iteration
startTxId = batch.get(batch.size() - 1).getTxID() + 1;
} while (!batch.isEmpty());
}
retrun totalProcessed;
}
@aryangupta1998 the test failure seems related to this change, can you take a look at it? |
What changes were proposed in this pull request?
In case of resetDeletedBlockRetryCount with --all option, scm takes lock and tries to get all the transaction with max retry and then updates DB with 0 count. In some large scale env this count can be huge which can lead to multiple problem.
i) Lock can lead to block all other normal operation.
ii) Since message is passed through ratis, which will fail because of size.
Instead of doing like above we should do this operation in batches to avoid long lock and ratis message size failure.
What is the link to the Apache JIRA
https://issues.apache.org/jira/browse/HDDS-11714
How was this patch tested?
Tested Manually.