Skip to content
This repository has been archived by the owner on Nov 14, 2024. It is now read-only.

optional validation of immutable ts on read operations #3414

Merged
merged 8 commits into from
Aug 16, 2018

Conversation

gozakdag
Copy link
Contributor

@gozakdag gozakdag commented Jul 25, 2018

Goals (and why):
Addressing this closed pr: #2996
Making lock validations optional for read operations.

Implementation Description (bullets):
Adding a configurable flag called validateLocksOnReads to TransactionManagers. It is set to true by default to conserve previous behavior. Validation after a read operation is done only if table is thoroughly swept and this flag is set to true. Validation at commit time is done if table is thoroughly swept, independent of validateLocksOnReads set to true or false.

Testing (What was existing testing like? What have you done to improve it?):
Adding two more test cases.

  • First test confirms that setting validateLocksOnReads to true causes validation to run after a read operation, even if the transaction is not committed.
  • Second test case sets validateLocksOnReads to false. This time immutable ts locks are not checked after a read operation; but it is checked when we commit the transaction.

I also tried to refactor tests a bit by creating a private method to generate SnapshotTransaction, as it is constructor is taking large number of parameters, and making it hard to read the test case. It still doesn't look great, maybe we can add a builder to be used only in tests?

Concerns (what feedback would you like?):

  • Setting validateLocksOnReads to false will cause giving up on idempotent read operations. Clients can have two different reads for same value in a transaction. This cannot cause a correctness problem, as transaction will fail at commit time; the way the transaction fails will change.
  • This adds yet another parameter to constructor of SnapshotTransaction, and TransactionManager :(

Where should we start reviewing?:
SnapshotTransaction.java

Priority (whenever / two weeks / yesterday):
1 week?


This change is Reviewable

@gozakdag gozakdag requested review from sandorw and tboam as code owners July 25, 2018 13:20
@j-baker
Copy link
Contributor

j-baker commented Jul 31, 2018

I would propose we make the transaction managers handle this safely? You need to validate before bubbling up any exception, basically

@sandorw
Copy link
Contributor

sandorw commented Jul 31, 2018

If we want to do that, we should wrap the task.execute(txn) call in AbstractTransactionManager, since we don't want to catch exceptions from the commit phase - this change only affects behavior during the task anyway, since it affects reads within the transaction. This way, if your code throws an IAE/ISE/NPE due to inconsistencies in the data it read because the lock checks were removed, it can be caught, the locks checked, and treated as a retriable exception instead.

Copy link
Contributor

@jeremyk-91 jeremyk-91 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes as written make sense. Though as @sandorw notes explicitly above, there is a behaviour change if my transaction task contains inconsistent reads followed by internal validation, which we should address.

Also, I'm pretty sure we want release notes.

return;
}
throwIfPreCommitRequirementsNotMet(null, timestamp);
}

private boolean isValidationNecessaryOnReads(TableReference tableRef) {
return isValidationNecessary(tableRef) && validateLocksOnReads;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably premature, but if in most usage validateLocksOnReads is going to be false, then flipping the arguments makes sense.

@@ -747,13 +750,17 @@ private static boolean isSingleton(Iterable<?> elements) {
};
}

private void validateExternalAndCommitLocksIfNecessary(TableReference tableRef, long timestamp) {
if (!isValidationNecessary(tableRef)) {
private void validateExternalAndCommitLocksOnReadIfNecessary(TableReference tableRef, long timestamp) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we rename this to validatePreCommitRequirementsOnReadIfNecessary? Mainly because this checks the pre-commit conditions too, which may not be 'external locks'

@tboam tboam assigned gozakdag and unassigned jeremyk-91 Aug 14, 2018
Copy link
Contributor

@sandorw sandorw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just needs release notes and a merge with develop.

this.delegate = delegate;
this.timelockService = timelockService;
this.immutableTsLock = immutableTsLock;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: whitespace

/**
* Best effort attempt to keep backwards compatibility while making immutableTs lock validation optional on reads.
* Validating immutableTs lock only on commits rather than on every read may cause the TransactionTask to throw
* an unexpected non-retriable error as reads are not idempotent. This wrapper task will convert the exception thrown
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two issues:

  • reads aren't idempotent (, because)
  • if the immutableTs lock is lost, sweep may remove data our transaction is reading, affecting the consistency of the data read

*/

package com.palantir.atlasdb.transaction.impl;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: whitespace

import com.palantir.lock.v2.LockToken;
import com.palantir.lock.v2.TimelockService;

public class LockCheckingTransactionTaskTest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice tests!

@gozakdag gozakdag merged commit c06b311 into develop Aug 16, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants