1
0
mirror of https://github.com/apple/foundationdb.git synced 2025-05-24 16:20:15 +08:00

Merge pull request from sfc-gh-etschannen/feature-bypass-unreadable

Added a new option to bypass unreadable protection in read your writes for calls to get
This commit is contained in:
A.J. Beamon 2021-05-04 11:35:44 -07:00 committed by GitHub
commit 1537019237
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 35 additions and 4 deletions

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

@ -28,7 +28,7 @@
class RYWIterator { class RYWIterator {
public: public:
RYWIterator(SnapshotCache* snapshotCache, WriteMap* writeMap) 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 }; enum SEGMENT_TYPE { UNKNOWN_RANGE, EMPTY_RANGE, KV };
static const SEGMENT_TYPE typeMap[12]; static const SEGMENT_TYPE typeMap[12];
@ -59,6 +59,8 @@ public:
void skipContiguousBack(KeyRef key); void skipContiguousBack(KeyRef key);
void bypassUnreadableProtection() { bypassUnreadable = true; }
WriteMap::iterator& extractWriteMapIterator(); WriteMap::iterator& extractWriteMapIterator();
// Really this should return an iterator by value, but for performance it's convenient to actually grab the internal // 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 // one. Consider copying the return value if performance isn't critical. If you modify the returned iterator, it
@ -72,6 +74,8 @@ private:
SnapshotCache::iterator cache; SnapshotCache::iterator cache;
WriteMap::iterator writes; WriteMap::iterator writes;
KeyValueRef temp; KeyValueRef temp;
bool bypassUnreadable; // When set, allows read from sections of keyspace that have become unreadable because of
// versionstamp operations
void updateCmp(); void updateCmp();
}; };

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

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

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

@ -192,6 +192,9 @@ description is not currently required but encouraged.
description="Enable tracing for all transactions. This is the default." /> description="Enable tracing for all transactions. This is the default." />
<Option name="distributed_transaction_trace_disable" code="601" <Option name="distributed_transaction_trace_disable" code="601"
description="Disable tracing for all transactions." /> 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. This sets the ``bypass_unreadable`` option of each transaction created by this database. See the transaction option description for more information."
defaultFor="1100"/>
</Scope> </Scope>
<Scope name="TransactionOption"> <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"/> 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" <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." /> 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. These reads will view versionstamp operations as if they were set operations that did not fill in the versionstamp." />
</Scope> </Scope>
<!-- The enumeration values matter - do not change them without <!-- The enumeration values matter - do not change them without

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