Better accounting for tenant prefixes when working with key size limits (#6973)
* Consider tenant prefix sizes when doing key size limit checks * Fix formatting
This commit is contained in:
parent
14e7738455
commit
79063d5fc4
|
@ -21,6 +21,7 @@
|
|||
#include "fdbclient/Knobs.h"
|
||||
#include "fdbclient/FDBTypes.h"
|
||||
#include "fdbclient/SystemData.h"
|
||||
#include "fdbclient/Tenant.h"
|
||||
#include "flow/UnitTest.h"
|
||||
|
||||
#define init(...) KNOB_FN(__VA_ARGS__, INIT_ATOMIC_KNOB, INIT_KNOB)(__VA_ARGS__)
|
||||
|
@ -82,6 +83,7 @@ void ClientKnobs::initialize(Randomize randomize) {
|
|||
init( CHANGE_FEED_CACHE_SIZE, 100000 ); if( randomize && BUGGIFY ) CHANGE_FEED_CACHE_SIZE = 1;
|
||||
init( CHANGE_FEED_POP_TIMEOUT, 5.0 );
|
||||
init( CHANGE_FEED_STREAM_MIN_BYTES, 1e4 ); if( randomize && BUGGIFY ) CHANGE_FEED_STREAM_MIN_BYTES = 1;
|
||||
init( TENANT_PREFIX_SIZE_LIMIT, 28 ); ASSERT(TENANT_PREFIX_SIZE_LIMIT >= TenantMapEntry::ROOT_PREFIX_SIZE); // includes 8-byte ID and optional tenant subspace
|
||||
|
||||
init( MAX_BATCH_SIZE, 1000 ); if( randomize && BUGGIFY ) MAX_BATCH_SIZE = 1;
|
||||
init( GRV_BATCH_TIMEOUT, 0.005 ); if( randomize && BUGGIFY ) GRV_BATCH_TIMEOUT = 0.1;
|
||||
|
|
|
@ -81,6 +81,7 @@ public:
|
|||
int64_t CHANGE_FEED_CACHE_SIZE;
|
||||
double CHANGE_FEED_POP_TIMEOUT;
|
||||
int64_t CHANGE_FEED_STREAM_MIN_BYTES;
|
||||
int64_t TENANT_PREFIX_SIZE_LIMIT;
|
||||
|
||||
int MAX_BATCH_SIZE;
|
||||
double GRV_BATCH_TIMEOUT;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "fdbclient/FDBTypes.h"
|
||||
#include "fdbclient/Knobs.h"
|
||||
#include "fdbclient/NativeAPI.actor.h"
|
||||
|
||||
KeyRef keyBetween(const KeyRangeRef& keys) {
|
||||
int pos = 0; // will be the position of the first difference between keys.begin and keys.end
|
||||
|
@ -40,16 +41,14 @@ KeyRef keyBetween(const KeyRangeRef& keys) {
|
|||
}
|
||||
|
||||
void KeySelectorRef::setKey(KeyRef const& key) {
|
||||
// There are no keys in the database with size greater than KEY_SIZE_LIMIT, so if this key selector has a key
|
||||
// There are no keys in the database with size greater than the max key size, so if this key selector has a key
|
||||
// which is large, then we can translate it to an equivalent key selector with a smaller key
|
||||
if (key.size() >
|
||||
(key.startsWith(LiteralStringRef("\xff")) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
this->key = key.substr(0,
|
||||
(key.startsWith(LiteralStringRef("\xff")) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
else
|
||||
int64_t maxKeySize = getMaxKeySize(key);
|
||||
if (key.size() > maxKeySize) {
|
||||
this->key = key.substr(0, maxKeySize + 1);
|
||||
} else {
|
||||
this->key = key;
|
||||
}
|
||||
}
|
||||
|
||||
void KeySelectorRef::setKeyUnlimited(KeyRef const& key) {
|
||||
|
|
|
@ -746,6 +746,17 @@ Future<Optional<TenantMapEntry>> createTenantTransaction(Transaction tr, TenantN
|
|||
state Optional<Value> lastIdVal = wait(safeThreadFutureToFuture(lastIdFuture));
|
||||
Optional<Value> tenantDataPrefix = wait(safeThreadFutureToFuture(tenantDataPrefixFuture));
|
||||
|
||||
if (tenantDataPrefix.present() &&
|
||||
tenantDataPrefix.get().size() + TenantMapEntry::ROOT_PREFIX_SIZE > CLIENT_KNOBS->TENANT_PREFIX_SIZE_LIMIT) {
|
||||
TraceEvent(SevWarnAlways, "TenantPrefixTooLarge")
|
||||
.detail("TenantSubspace", tenantDataPrefix.get())
|
||||
.detail("TenantSubspaceLength", tenantDataPrefix.get().size())
|
||||
.detail("RootPrefixLength", TenantMapEntry::ROOT_PREFIX_SIZE)
|
||||
.detail("MaxTenantPrefixSize", CLIENT_KNOBS->TENANT_PREFIX_SIZE_LIMIT);
|
||||
|
||||
throw client_invalid_operation();
|
||||
}
|
||||
|
||||
state TenantMapEntry newTenant(lastIdVal.present() ? TenantMapEntry::prefixToId(lastIdVal.get()) + 1 : 0,
|
||||
tenantDataPrefix.present() ? (KeyRef)tenantDataPrefix.get() : ""_sr);
|
||||
|
||||
|
|
|
@ -5100,10 +5100,10 @@ Future<Optional<Value>> Transaction::get(const Key& key, Snapshot snapshot) {
|
|||
++trState->cx->transactionGetValueRequests;
|
||||
// ASSERT (key < allKeys.end);
|
||||
|
||||
// There are no keys in the database with size greater than KEY_SIZE_LIMIT
|
||||
if (key.size() >
|
||||
(key.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
// There are no keys in the database with size greater than the max key size
|
||||
if (key.size() > getMaxReadKeySize(key)) {
|
||||
return Optional<Value>();
|
||||
}
|
||||
|
||||
auto ver = getReadVersion();
|
||||
|
||||
|
@ -5484,23 +5484,19 @@ Future<Void> Transaction::getRangeStream(const PromiseStream<RangeResult>& resul
|
|||
void Transaction::addReadConflictRange(KeyRangeRef const& keys) {
|
||||
ASSERT(!keys.empty());
|
||||
|
||||
// There aren't any keys in the database with size larger than KEY_SIZE_LIMIT, so if range contains large keys
|
||||
// There aren't any keys in the database with size larger than the max key size, so if range contains large keys
|
||||
// we can translate it to an equivalent one with smaller keys
|
||||
KeyRef begin = keys.begin;
|
||||
KeyRef end = keys.end;
|
||||
|
||||
if (begin.size() >
|
||||
(begin.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
begin = begin.substr(
|
||||
0,
|
||||
(begin.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
if (end.size() >
|
||||
(end.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
end = end.substr(
|
||||
0,
|
||||
(end.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
int64_t beginMaxSize = getMaxReadKeySize(begin);
|
||||
int64_t endMaxSize = getMaxReadKeySize(end);
|
||||
if (begin.size() > beginMaxSize) {
|
||||
begin = begin.substr(0, beginMaxSize + 1);
|
||||
}
|
||||
if (end.size() > endMaxSize) {
|
||||
end = end.substr(0, endMaxSize + 1);
|
||||
}
|
||||
|
||||
KeyRangeRef r = KeyRangeRef(begin, end);
|
||||
|
||||
|
@ -5522,8 +5518,7 @@ void Transaction::makeSelfConflicting() {
|
|||
|
||||
void Transaction::set(const KeyRef& key, const ValueRef& value, AddConflictRange addConflictRange) {
|
||||
++trState->cx->transactionSetMutations;
|
||||
if (key.size() >
|
||||
(key.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
if (key.size() > getMaxWriteKeySize(key, trState->options.rawAccess))
|
||||
throw key_too_large();
|
||||
if (value.size() > CLIENT_KNOBS->VALUE_SIZE_LIMIT)
|
||||
throw value_too_large();
|
||||
|
@ -5544,8 +5539,7 @@ void Transaction::atomicOp(const KeyRef& key,
|
|||
MutationRef::Type operationType,
|
||||
AddConflictRange addConflictRange) {
|
||||
++trState->cx->transactionAtomicMutations;
|
||||
if (key.size() >
|
||||
(key.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
if (key.size() > getMaxWriteKeySize(key, trState->options.rawAccess))
|
||||
throw key_too_large();
|
||||
if (operand.size() > CLIENT_KNOBS->VALUE_SIZE_LIMIT)
|
||||
throw value_too_large();
|
||||
|
@ -5578,20 +5572,16 @@ void Transaction::clear(const KeyRangeRef& range, AddConflictRange addConflictRa
|
|||
KeyRef begin = range.begin;
|
||||
KeyRef end = range.end;
|
||||
|
||||
// There aren't any keys in the database with size larger than KEY_SIZE_LIMIT, so if range contains large keys
|
||||
// There aren't any keys in the database with size larger than the max key size, so if range contains large keys
|
||||
// we can translate it to an equivalent one with smaller keys
|
||||
if (begin.size() >
|
||||
(begin.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
begin = begin.substr(
|
||||
0,
|
||||
(begin.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
if (end.size() >
|
||||
(end.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
end = end.substr(
|
||||
0,
|
||||
(end.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
int64_t beginMaxSize = getMaxClearKeySize(begin);
|
||||
int64_t endMaxSize = getMaxClearKeySize(end);
|
||||
if (begin.size() > beginMaxSize) {
|
||||
begin = begin.substr(0, beginMaxSize + 1);
|
||||
}
|
||||
if (end.size() > endMaxSize) {
|
||||
end = end.substr(0, endMaxSize + 1);
|
||||
}
|
||||
|
||||
auto r = KeyRangeRef(req.arena, KeyRangeRef(begin, end));
|
||||
if (r.empty())
|
||||
|
@ -5604,10 +5594,10 @@ void Transaction::clear(const KeyRangeRef& range, AddConflictRange addConflictRa
|
|||
}
|
||||
void Transaction::clear(const KeyRef& key, AddConflictRange addConflictRange) {
|
||||
++trState->cx->transactionClearMutations;
|
||||
// There aren't any keys in the database with size larger than KEY_SIZE_LIMIT
|
||||
if (key.size() >
|
||||
(key.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
// There aren't any keys in the database with size larger than the max key size
|
||||
if (key.size() > getMaxClearKeySize(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& req = tr;
|
||||
auto& t = req.transaction;
|
||||
|
@ -5626,24 +5616,19 @@ void Transaction::addWriteConflictRange(const KeyRangeRef& keys) {
|
|||
auto& req = tr;
|
||||
auto& t = req.transaction;
|
||||
|
||||
// There aren't any keys in the database with size larger than KEY_SIZE_LIMIT, so if range contains large keys
|
||||
// There aren't any keys in the database with size larger than the max key size, so if range contains large keys
|
||||
// we can translate it to an equivalent one with smaller keys
|
||||
KeyRef begin = keys.begin;
|
||||
KeyRef end = keys.end;
|
||||
|
||||
if (begin.size() >
|
||||
(begin.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
begin = begin.substr(
|
||||
0,
|
||||
(begin.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
if (end.size() >
|
||||
(end.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
end = end.substr(
|
||||
0,
|
||||
(end.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
|
||||
int64_t beginMaxSize = getMaxKeySize(begin);
|
||||
int64_t endMaxSize = getMaxKeySize(end);
|
||||
if (begin.size() > beginMaxSize) {
|
||||
begin = begin.substr(0, beginMaxSize + 1);
|
||||
}
|
||||
if (end.size() > endMaxSize) {
|
||||
end = end.substr(0, endMaxSize + 1);
|
||||
}
|
||||
KeyRangeRef r = KeyRangeRef(begin, end);
|
||||
|
||||
if (r.empty()) {
|
||||
|
@ -9395,3 +9380,21 @@ ACTOR Future<Void> waitPurgeGranulesCompleteActor(Reference<DatabaseContext> db,
|
|||
Future<Void> DatabaseContext::waitPurgeGranulesComplete(Key purgeKey) {
|
||||
return waitPurgeGranulesCompleteActor(Reference<DatabaseContext>::addRef(this), purgeKey);
|
||||
}
|
||||
|
||||
int64_t getMaxKeySize(KeyRef const& key) {
|
||||
return getMaxWriteKeySize(key, true);
|
||||
}
|
||||
|
||||
int64_t getMaxReadKeySize(KeyRef const& key) {
|
||||
return getMaxKeySize(key);
|
||||
}
|
||||
|
||||
int64_t getMaxWriteKeySize(KeyRef const& key, bool hasRawAccess) {
|
||||
int64_t tenantSize = hasRawAccess ? CLIENT_KNOBS->TENANT_PREFIX_SIZE_LIMIT : 0;
|
||||
return key.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT + tenantSize;
|
||||
}
|
||||
|
||||
int64_t getMaxClearKeySize(KeyRef const& key) {
|
||||
return getMaxKeySize(key);
|
||||
}
|
|
@ -539,5 +539,19 @@ ACTOR Future<std::vector<std::pair<UID, StorageWiggleValue>>> readStorageWiggleV
|
|||
bool primary,
|
||||
bool use_system_priority);
|
||||
|
||||
// Returns the maximum legal size of a key. This size will be determined by the prefix of the passed in key
|
||||
// (system keys have a larger maximum size). This should be used for generic max key size requests.
|
||||
int64_t getMaxKeySize(KeyRef const& key);
|
||||
|
||||
// Returns the maximum legal size of a key that can be read. Keys larger than this will be assumed not to exist.
|
||||
int64_t getMaxReadKeySize(KeyRef const& key);
|
||||
|
||||
// Returns the maximum legal size of a key that can be written. If using raw access, writes to normal keys will
|
||||
// be allowed to be slighly larger to accommodate the prefix.
|
||||
int64_t getMaxWriteKeySize(KeyRef const& key, bool hasRawAccess);
|
||||
|
||||
// Returns the maximum legal size of a key that can be cleared. Keys larger than this will be assumed not to exist.
|
||||
int64_t getMaxClearKeySize(KeyRef const& key);
|
||||
|
||||
#include "flow/unactorcompiler.h"
|
||||
#endif
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "fdbclient/ReadYourWrites.h"
|
||||
#include "fdbclient/NativeAPI.actor.h"
|
||||
#include "fdbclient/Atomic.h"
|
||||
#include "fdbclient/DatabaseContext.h"
|
||||
#include "fdbclient/SpecialKeySpace.actor.h"
|
||||
|
@ -1578,10 +1579,10 @@ Future<Optional<Value>> ReadYourWritesTransaction::get(const Key& key, Snapshot
|
|||
if (key >= getMaxReadKey() && key != metadataVersionKey)
|
||||
return key_outside_legal_range();
|
||||
|
||||
// There are no keys in the database with size greater than KEY_SIZE_LIMIT
|
||||
if (key.size() >
|
||||
(key.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
// There are no keys in the database with size greater than the max key size
|
||||
if (key.size() > getMaxReadKeySize(key)) {
|
||||
return Optional<Value>();
|
||||
}
|
||||
|
||||
Future<Optional<Value>> result = RYWImpl::readWithConflictRange(this, RYWImpl::GetValueReq(key), snapshot);
|
||||
reading.add(success(result));
|
||||
|
@ -1822,23 +1823,19 @@ void ReadYourWritesTransaction::addReadConflictRange(KeyRangeRef const& keys) {
|
|||
}
|
||||
}
|
||||
|
||||
// There aren't any keys in the database with size larger than KEY_SIZE_LIMIT, so if range contains large keys
|
||||
// There aren't any keys in the database with size larger than max key size, so if range contains large keys
|
||||
// we can translate it to an equivalent one with smaller keys
|
||||
KeyRef begin = keys.begin;
|
||||
KeyRef end = keys.end;
|
||||
|
||||
if (begin.size() >
|
||||
(begin.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
begin = begin.substr(
|
||||
0,
|
||||
(begin.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
if (end.size() >
|
||||
(end.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
end = end.substr(
|
||||
0,
|
||||
(end.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
int64_t beginMaxSize = getMaxReadKeySize(begin);
|
||||
int64_t endMaxSize = getMaxReadKeySize(end);
|
||||
if (begin.size() > beginMaxSize) {
|
||||
begin = begin.substr(0, beginMaxSize + 1);
|
||||
}
|
||||
if (end.size() > endMaxSize) {
|
||||
end = end.substr(0, endMaxSize + 1);
|
||||
}
|
||||
|
||||
KeyRangeRef r = KeyRangeRef(begin, end);
|
||||
|
||||
|
@ -2111,9 +2108,9 @@ void ReadYourWritesTransaction::atomicOp(const KeyRef& key, const ValueRef& oper
|
|||
if (!isValidMutationType(operationType) || !isAtomicOp((MutationRef::Type)operationType))
|
||||
throw invalid_mutation_type();
|
||||
|
||||
if (key.size() >
|
||||
(key.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
if (key.size() > getMaxWriteKeySize(key, getTransactionState()->options.rawAccess)) {
|
||||
throw key_too_large();
|
||||
}
|
||||
if (operand.size() > CLIENT_KNOBS->VALUE_SIZE_LIMIT)
|
||||
throw value_too_large();
|
||||
|
||||
|
@ -2218,9 +2215,9 @@ void ReadYourWritesTransaction::set(const KeyRef& key, const ValueRef& value) {
|
|||
}
|
||||
|
||||
// TODO: check transaction size here
|
||||
if (key.size() >
|
||||
(key.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
if (key.size() > getMaxWriteKeySize(key, getTransactionState()->options.rawAccess)) {
|
||||
throw key_too_large();
|
||||
}
|
||||
if (value.size() > CLIENT_KNOBS->VALUE_SIZE_LIMIT)
|
||||
throw value_too_large();
|
||||
|
||||
|
@ -2254,23 +2251,19 @@ void ReadYourWritesTransaction::clear(const KeyRangeRef& range) {
|
|||
return tr.clear(range, addWriteConflict);
|
||||
}
|
||||
|
||||
// There aren't any keys in the database with size larger than KEY_SIZE_LIMIT, so if range contains large keys
|
||||
// There aren't any keys in the database with size larger than the max key size, so if range contains large keys
|
||||
// we can translate it to an equivalent one with smaller keys
|
||||
KeyRef begin = range.begin;
|
||||
KeyRef end = range.end;
|
||||
|
||||
if (begin.size() >
|
||||
(begin.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
begin = begin.substr(
|
||||
0,
|
||||
(begin.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
if (end.size() >
|
||||
(end.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
end = end.substr(
|
||||
0,
|
||||
(end.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
int64_t beginMaxSize = getMaxClearKeySize(begin);
|
||||
int64_t endMaxSize = getMaxClearKeySize(end);
|
||||
if (begin.size() > beginMaxSize) {
|
||||
begin = begin.substr(0, beginMaxSize + 1);
|
||||
}
|
||||
if (end.size() > endMaxSize) {
|
||||
end = end.substr(0, endMaxSize + 1);
|
||||
}
|
||||
|
||||
KeyRangeRef r = KeyRangeRef(begin, end);
|
||||
|
||||
|
@ -2300,9 +2293,9 @@ void ReadYourWritesTransaction::clear(const KeyRef& key) {
|
|||
if (key >= getMaxWriteKey())
|
||||
throw key_outside_legal_range();
|
||||
|
||||
if (key.size() >
|
||||
(key.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
if (key.size() > getMaxClearKeySize(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.readYourWritesDisabled) {
|
||||
return tr.clear(key, addWriteConflict);
|
||||
|
@ -2332,9 +2325,9 @@ Future<Void> ReadYourWritesTransaction::watch(const Key& key) {
|
|||
if (key >= allKeys.end || (key >= getMaxReadKey() && key != metadataVersionKey && tr.apiVersionAtLeast(300)))
|
||||
return key_outside_legal_range();
|
||||
|
||||
if (key.size() >
|
||||
(key.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
if (key.size() > getMaxWriteKeySize(key, getTransactionState()->options.rawAccess)) {
|
||||
return key_too_large();
|
||||
}
|
||||
|
||||
return RYWImpl::watch(this, key);
|
||||
}
|
||||
|
@ -2350,23 +2343,19 @@ void ReadYourWritesTransaction::addWriteConflictRange(KeyRangeRef const& keys) {
|
|||
}
|
||||
}
|
||||
|
||||
// There aren't any keys in the database with size larger than KEY_SIZE_LIMIT, so if range contains large keys
|
||||
// There aren't any keys in the database with size larger than the max key size, so if range contains large keys
|
||||
// we can translate it to an equivalent one with smaller keys
|
||||
KeyRef begin = keys.begin;
|
||||
KeyRef end = keys.end;
|
||||
|
||||
if (begin.size() >
|
||||
(begin.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
begin = begin.substr(
|
||||
0,
|
||||
(begin.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
if (end.size() >
|
||||
(end.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
end = end.substr(
|
||||
0,
|
||||
(end.startsWith(systemKeys.begin) ? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT : CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1);
|
||||
int64_t beginMaxSize = getMaxKeySize(begin);
|
||||
int64_t endMaxSize = getMaxKeySize(end);
|
||||
if (begin.size() > beginMaxSize) {
|
||||
begin = begin.substr(0, beginMaxSize + 1);
|
||||
}
|
||||
if (end.size() > endMaxSize) {
|
||||
end = end.substr(0, endMaxSize + 1);
|
||||
}
|
||||
|
||||
KeyRangeRef r = KeyRangeRef(begin, end);
|
||||
|
||||
|
|
|
@ -48,6 +48,8 @@ struct TenantMapEntry {
|
|||
int64_t id;
|
||||
Key prefix;
|
||||
|
||||
constexpr static int ROOT_PREFIX_SIZE = sizeof(id);
|
||||
|
||||
private:
|
||||
void initPrefix(KeyRef subspace) {
|
||||
ASSERT(id >= 0);
|
||||
|
|
|
@ -329,9 +329,7 @@ struct FuzzApiCorrectnessWorkload : TestWorkload {
|
|||
for (int j = i; j < end; j++) {
|
||||
if (deterministicRandom()->random01() < self->initialKeyDensity) {
|
||||
Key key = self->getKeyForIndex(tenantNum, j);
|
||||
if (key.size() <= (key.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT)) {
|
||||
if (key.size() <= getMaxWriteKeySize(key, false)) {
|
||||
Value value = self->getRandomValue();
|
||||
value = value.substr(
|
||||
0, std::min<int>(value.size(), CLIENT_KNOBS->VALUE_SIZE_LIMIT));
|
||||
|
@ -1091,24 +1089,22 @@ struct FuzzApiCorrectnessWorkload : TestWorkload {
|
|||
pos = littleEndian32(*(int32_t*)&value.end()[-4]);
|
||||
}
|
||||
|
||||
contract = {
|
||||
std::make_pair(error_code_key_too_large,
|
||||
ExceptionContract::requiredIf(key.size() > (key.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT))),
|
||||
std::make_pair(error_code_value_too_large,
|
||||
ExceptionContract::requiredIf(value.size() > CLIENT_KNOBS->VALUE_SIZE_LIMIT)),
|
||||
std::make_pair(
|
||||
error_code_invalid_mutation_type,
|
||||
ExceptionContract::requiredIf(!isValidMutationType(op) || !isAtomicOp((MutationRef::Type)op))),
|
||||
std::make_pair(error_code_key_outside_legal_range,
|
||||
ExceptionContract::requiredIf((key >= workload->getMaxKey(tr)))),
|
||||
std::make_pair(
|
||||
error_code_client_invalid_operation,
|
||||
ExceptionContract::requiredIf(
|
||||
(op == MutationRef::SetVersionstampedKey && (pos < 0 || pos + 10 > key.size() - 4)) ||
|
||||
(op == MutationRef::SetVersionstampedValue && (pos < 0 || pos + 10 > value.size() - 4))))
|
||||
};
|
||||
contract = { std::make_pair(error_code_key_too_large,
|
||||
key.size() > getMaxWriteKeySize(key, true) ? ExceptionContract::Always
|
||||
: key.size() > getMaxWriteKeySize(key, false) ? ExceptionContract::Possible
|
||||
: ExceptionContract::Never),
|
||||
std::make_pair(error_code_value_too_large,
|
||||
ExceptionContract::requiredIf(value.size() > CLIENT_KNOBS->VALUE_SIZE_LIMIT)),
|
||||
std::make_pair(error_code_invalid_mutation_type,
|
||||
ExceptionContract::requiredIf(!isValidMutationType(op) ||
|
||||
!isAtomicOp((MutationRef::Type)op))),
|
||||
std::make_pair(error_code_key_outside_legal_range,
|
||||
ExceptionContract::requiredIf((key >= workload->getMaxKey(tr)))),
|
||||
std::make_pair(error_code_client_invalid_operation,
|
||||
ExceptionContract::requiredIf((op == MutationRef::SetVersionstampedKey &&
|
||||
(pos < 0 || pos + 10 > key.size() - 4)) ||
|
||||
(op == MutationRef::SetVersionstampedValue &&
|
||||
(pos < 0 || pos + 10 > value.size() - 4)))) };
|
||||
}
|
||||
|
||||
void callback(Reference<ITransaction> tr) override { tr->atomicOp(key, value, (FDBMutationTypes::Option)op); }
|
||||
|
@ -1131,11 +1127,10 @@ struct FuzzApiCorrectnessWorkload : TestWorkload {
|
|||
key = makeKey();
|
||||
}
|
||||
value = makeValue();
|
||||
contract = { std::make_pair(
|
||||
error_code_key_too_large,
|
||||
ExceptionContract::requiredIf(key.size() > (key.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT))),
|
||||
contract = { std::make_pair(error_code_key_too_large,
|
||||
key.size() > getMaxWriteKeySize(key, true) ? ExceptionContract::Always
|
||||
: key.size() > getMaxWriteKeySize(key, false) ? ExceptionContract::Possible
|
||||
: ExceptionContract::Never),
|
||||
std::make_pair(error_code_value_too_large,
|
||||
ExceptionContract::requiredIf(value.size() > CLIENT_KNOBS->VALUE_SIZE_LIMIT)),
|
||||
std::make_pair(error_code_key_outside_legal_range,
|
||||
|
@ -1268,11 +1263,11 @@ struct FuzzApiCorrectnessWorkload : TestWorkload {
|
|||
TestWatch(unsigned int id, FuzzApiCorrectnessWorkload* workload, Reference<ITransaction> tr)
|
||||
: BaseTest(id, workload, "TestWatch") {
|
||||
key = makeKey();
|
||||
contract = { std::make_pair(
|
||||
error_code_key_too_large,
|
||||
ExceptionContract::requiredIf(key.size() > (key.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT))),
|
||||
printf("Watching: %d %s\n", key.size(), printable(key.substr(0, std::min(key.size(), 20))).c_str());
|
||||
contract = { std::make_pair(error_code_key_too_large,
|
||||
key.size() > getMaxWriteKeySize(key, true) ? ExceptionContract::Always
|
||||
: key.size() > getMaxWriteKeySize(key, false) ? ExceptionContract::Possible
|
||||
: ExceptionContract::Never),
|
||||
std::make_pair(error_code_watches_disabled, ExceptionContract::Possible),
|
||||
std::make_pair(error_code_key_outside_legal_range,
|
||||
ExceptionContract::requiredIf((key >= workload->getMaxKey(tr)))),
|
||||
|
|
|
@ -653,9 +653,7 @@ struct WriteDuringReadWorkload : TestWorkload {
|
|||
for (int j = i; j < end; j++) {
|
||||
if (deterministicRandom()->random01() < self->initialKeyDensity) {
|
||||
Key key = self->getKeyForIndex(j);
|
||||
if (key.size() <= (key.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT)) {
|
||||
if (key.size() <= getMaxWriteKeySize(key, false)) {
|
||||
Value value = self->getRandomValue();
|
||||
value =
|
||||
value.substr(0, std::min<int>(value.size(), CLIENT_KNOBS->VALUE_SIZE_LIMIT));
|
||||
|
@ -898,18 +896,10 @@ struct WriteDuringReadWorkload : TestWorkload {
|
|||
tr.clear(range);
|
||||
if (!noConflict) {
|
||||
KeyRangeRef conflict(
|
||||
range.begin.substr(0,
|
||||
std::min<int>(range.begin.size(),
|
||||
(range.begin.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1)),
|
||||
range.end.substr(0,
|
||||
std::min<int>(range.end.size(),
|
||||
(range.end.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1)));
|
||||
range.begin.substr(
|
||||
0, std::min<int>(range.begin.size(), getMaxClearKeySize(range.begin) + 1)),
|
||||
range.end.substr(
|
||||
0, std::min<int>(range.end.size(), getMaxClearKeySize(range.end) + 1)));
|
||||
self->addedConflicts.insert(conflict, true);
|
||||
}
|
||||
self->memoryDatabase.erase(self->memoryDatabase.lower_bound(range.begin),
|
||||
|
@ -922,9 +912,7 @@ struct WriteDuringReadWorkload : TestWorkload {
|
|||
if (noConflict)
|
||||
tr.setOption(FDBTransactionOptions::NEXT_WRITE_NO_WRITE_CONFLICT_RANGE);
|
||||
tr.clear(key);
|
||||
if (!noConflict && key.size() <= (key.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT)) {
|
||||
if (!noConflict && key.size() <= getMaxClearKeySize(key)) {
|
||||
self->addedConflicts.insert(key, true);
|
||||
}
|
||||
self->memoryDatabase.erase(key);
|
||||
|
@ -936,18 +924,9 @@ struct WriteDuringReadWorkload : TestWorkload {
|
|||
//TraceEvent("WDRAddWriteConflict").detail("Range", range);
|
||||
tr.addWriteConflictRange(range);
|
||||
KeyRangeRef conflict(
|
||||
range.begin.substr(0,
|
||||
std::min<int>(range.begin.size(),
|
||||
(range.begin.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1)),
|
||||
range.end.substr(0,
|
||||
std::min<int>(range.end.size(),
|
||||
(range.end.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1)));
|
||||
range.begin.substr(
|
||||
0, std::min<int>(range.begin.size(), getMaxKeySize(range.begin) + 1)),
|
||||
range.end.substr(0, std::min<int>(range.end.size(), getMaxKeySize(range.end) + 1)));
|
||||
self->addedConflicts.insert(conflict, true);
|
||||
} else if (operationType == 8 && !disableDelay) {
|
||||
double maxTime = 6.0;
|
||||
|
@ -991,18 +970,10 @@ struct WriteDuringReadWorkload : TestWorkload {
|
|||
tr.atomicOp(versionStampKey, value, MutationRef::SetVersionstampedKey);
|
||||
tr.clear(range);
|
||||
KeyRangeRef conflict(
|
||||
range.begin.substr(0,
|
||||
std::min<int>(range.begin.size(),
|
||||
(range.begin.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1)),
|
||||
range.end.substr(0,
|
||||
std::min<int>(range.end.size(),
|
||||
(range.end.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT) +
|
||||
1)));
|
||||
range.begin.substr(
|
||||
0, std::min<int>(range.begin.size(), getMaxClearKeySize(range.begin) + 1)),
|
||||
range.end.substr(
|
||||
0, std::min<int>(range.end.size(), getMaxClearKeySize(range.end) + 1)));
|
||||
self->addedConflicts.insert(conflict, true);
|
||||
self->memoryDatabase.erase(self->memoryDatabase.lower_bound(range.begin),
|
||||
self->memoryDatabase.lower_bound(range.end));
|
||||
|
@ -1043,10 +1014,9 @@ struct WriteDuringReadWorkload : TestWorkload {
|
|||
tr.setOption(FDBTransactionOptions::NEXT_WRITE_NO_WRITE_CONFLICT_RANGE);
|
||||
tr.atomicOp(key, value, opType);
|
||||
//TraceEvent("WDRAtomicOpSuccess").detail("Key", key).detail("Value", value.size());
|
||||
if (!noConflict && key.size() <= (key.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
if (!noConflict && key.size() <= getMaxWriteKeySize(key, false)) {
|
||||
self->addedConflicts.insert(key, true);
|
||||
}
|
||||
Optional<Value> existing = self->memoryGet(&self->memoryDatabase, key);
|
||||
self->memoryDatabase[key] =
|
||||
self->applyAtomicOp(existing.present() ? Optional<StringRef>(existing.get())
|
||||
|
@ -1063,10 +1033,9 @@ struct WriteDuringReadWorkload : TestWorkload {
|
|||
if (noConflict)
|
||||
tr.setOption(FDBTransactionOptions::NEXT_WRITE_NO_WRITE_CONFLICT_RANGE);
|
||||
tr.set(key, value);
|
||||
if (!noConflict && key.size() <= (key.startsWith(systemKeys.begin)
|
||||
? CLIENT_KNOBS->SYSTEM_KEY_SIZE_LIMIT
|
||||
: CLIENT_KNOBS->KEY_SIZE_LIMIT))
|
||||
if (!noConflict && key.size() <= getMaxWriteKeySize(key, false)) {
|
||||
self->addedConflicts.insert(key, true);
|
||||
}
|
||||
//TraceEvent("WDRSetSuccess").detail("Key", key).detail("Value", value.size());
|
||||
self->memoryDatabase[key] = value;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue