Added a new option to bypass unreadable protection in read your writes for calls to get

This commit is contained in:
Evan Tschannen 2021-04-28 16:22:34 -07:00
parent 54ed5de648
commit 709df795c0
7 changed files with 35 additions and 4 deletions

View File

@ -42,7 +42,7 @@ const RYWIterator::SEGMENT_TYPE RYWIterator::typeMap[12] = {
};
RYWIterator::SEGMENT_TYPE RYWIterator::type() const {
if (is_unreadable())
if (is_unreadable() && !bypassUnreadable)
throw accessed_unreadable();
return typeMap[writes.type() * 3 + cache.type()];
@ -72,7 +72,7 @@ ExtStringRef RYWIterator::endKey() {
}
const KeyValueRef* RYWIterator::kv(Arena& arena) {
if (is_unreadable())
if (is_unreadable() && !bypassUnreadable)
throw accessed_unreadable();
if (writes.is_unmodified_range()) {

View File

@ -28,7 +28,7 @@
class RYWIterator {
public:
RYWIterator(SnapshotCache* snapshotCache, WriteMap* writeMap)
: cache(snapshotCache), writes(writeMap), begin_key_cmp(0), end_key_cmp(0) {}
: cache(snapshotCache), writes(writeMap), begin_key_cmp(0), end_key_cmp(0), bypassUnreadable(false) {}
enum SEGMENT_TYPE { UNKNOWN_RANGE, EMPTY_RANGE, KV };
static const SEGMENT_TYPE typeMap[12];
@ -59,6 +59,8 @@ public:
void skipContiguousBack(KeyRef key);
void bypassUnreadableProtection() { bypassUnreadable = true; }
WriteMap::iterator& extractWriteMapIterator();
// Really this should return an iterator by value, but for performance it's convenient to actually grab the internal
// one. Consider copying the return value if performance isn't critical. If you modify the returned iterator, it
@ -72,6 +74,7 @@ private:
SnapshotCache::iterator cache;
WriteMap::iterator writes;
KeyValueRef temp;
bool bypassUnreadable;
void updateCmp();
};

View File

@ -84,6 +84,9 @@ public:
static Future<Optional<Value>> read(ReadYourWritesTransaction* ryw, GetValueReq read, Iter* it) {
// This overload is required to provide postcondition: it->extractWriteMapIterator().segmentContains(read.key)
if (ryw->options.bypassUnreadable) {
it->bypassUnreadableProtection();
}
it->skip(read.key);
state bool dependent = it->is_dependent();
if (it->is_kv()) {
@ -2237,6 +2240,11 @@ void ReadYourWritesTransaction::setOptionImpl(FDBTransactionOptions::Option opti
validateOptionValue(value, false);
options.specialKeySpaceChangeConfiguration = true;
break;
case FDBTransactionOptions::BYPASS_UNREADABLE:
validateOptionValue(value, false);
TraceEvent("ReadVersionStampValueOptionSet");
options.bypassUnreadable = true;
break;
default:
break;
}

View File

@ -42,6 +42,7 @@ struct ReadYourWritesTransactionOptions {
double timeoutInSeconds;
int maxRetries;
int snapshotRywEnabled;
bool bypassUnreadable : 1;
ReadYourWritesTransactionOptions() {}
explicit ReadYourWritesTransactionOptions(Transaction const& tr);

View File

@ -203,6 +203,7 @@ public:
bool is_empty_range() const { return type() == EMPTY_RANGE; }
bool is_dependent() const { return false; }
bool is_unreadable() const { return false; }
void bypassUnreadableProtection() {}
ExtStringRef beginKey() const {
if (offset == 0) {

View File

@ -192,6 +192,9 @@ description is not currently required but encouraged.
description="Enable tracing for all transactions. This is the default." />
<Option name="distributed_transaction_trace_disable" code="601"
description="Disable tracing for all transactions." />
<Option name="transaction_bypass_unreadable" code="700"
description="Allows ``get`` operations to read from sections of keyspace that have become unreadable because of versionstamp operations."
defaultFor="1100"/>
</Scope>
<Scope name="TransactionOption">
@ -284,6 +287,8 @@ description is not currently required but encouraged.
description="Adds a parent to the Span of this transaction. Used for transaction tracing. A span can be identified with any 16 bytes"/>
<Option name="expensive_clear_cost_estimation_enable" code="1000"
description="Asks storage servers for how many bytes a clear key range contains. Otherwise uses the location cache to roughly estimate this." />
<Option name="bypass_unreadable" code="1100"
description="Allows ``get`` operations to read from sections of keyspace that have become unreadable because of versionstamp operations." />
</Scope>
<!-- The enumeration values matter - do not change them without

View File

@ -313,6 +313,10 @@ struct UnreadableWorkload : TestWorkload {
state bool snapshot;
state KeySelectorRef begin;
state KeySelectorRef end;
state bool bypassUnreadable = deterministicRandom()->coinflip();
if (readVerisonStampValues) {
tr.setOption(FDBTransactionOptions::BYPASS_UNREADABLE);
}
setMap[normalKeys.begin] = ValueRef();
setMap[normalKeys.end] = ValueRef();
@ -377,6 +381,9 @@ struct UnreadableWorkload : TestWorkload {
setMap = std::map<KeyRef, ValueRef>();
unreadableMap = KeyRangeMap<bool>();
tr = ReadYourWritesTransaction(cx);
if (bypassUnreadable) {
tr.setOption(FDBTransactionOptions::BYPASS_UNREADABLE);
}
arena = Arena();
setMap[normalKeys.begin] = ValueRef();
@ -422,6 +429,9 @@ struct UnreadableWorkload : TestWorkload {
setMap = std::map<KeyRef, ValueRef>();
unreadableMap = KeyRangeMap<bool>();
tr = ReadYourWritesTransaction(cx);
if (bypassUnreadable) {
tr.setOption(FDBTransactionOptions::BYPASS_UNREADABLE);
}
arena = Arena();
setMap[normalKeys.begin] = ValueRef();
@ -441,7 +451,7 @@ struct UnreadableWorkload : TestWorkload {
if (!value.isError() || value.getError().code() == error_code_accessed_unreadable) {
//TraceEvent("RYWT_Get").detail("Key", printable(key)).detail("IsUnreadable", value.isError());
if (snapshot) {
if (snapshot || bypassUnreadable) {
ASSERT(!value.isError());
} else {
ASSERT(unreadableMap[key] == value.isError());
@ -451,6 +461,9 @@ struct UnreadableWorkload : TestWorkload {
setMap = std::map<KeyRef, ValueRef>();
unreadableMap = KeyRangeMap<bool>();
tr = ReadYourWritesTransaction(cx);
if (bypassUnreadable) {
tr.setOption(FDBTransactionOptions::BYPASS_UNREADABLE);
}
arena = Arena();
setMap[normalKeys.begin] = ValueRef();