Merge pull request #8803 from sfc-gh-akejriwal/commitproxies
Add a transaction option to bypass storage quota enforcement
This commit is contained in:
commit
3036f2458f
|
@ -497,6 +497,11 @@ func (o TransactionOptions) SetRawAccess() error {
|
|||
return o.setOpt(303, nil)
|
||||
}
|
||||
|
||||
// Allows this transaction to bypass storage quota enforcement. Should only be used for transactions that directly or indirectly decrease the size of the tenant group's data.
|
||||
func (o TransactionOptions) SetBypassStorageQuota() error {
|
||||
return o.setOpt(304, nil)
|
||||
}
|
||||
|
||||
// Not yet implemented.
|
||||
func (o TransactionOptions) SetDebugRetryLogging(param string) error {
|
||||
return o.setOpt(401, []byte(param))
|
||||
|
|
|
@ -5953,6 +5953,7 @@ void TransactionOptions::clear() {
|
|||
useGrvCache = false;
|
||||
skipGrvCache = false;
|
||||
rawAccess = false;
|
||||
bypassStorageQuota = false;
|
||||
}
|
||||
|
||||
TransactionOptions::TransactionOptions() {
|
||||
|
@ -6694,6 +6695,9 @@ Future<Void> Transaction::commitMutations() {
|
|||
if (trState->options.firstInBatch) {
|
||||
tr.flags = tr.flags | CommitTransactionRequest::FLAG_FIRST_IN_BATCH;
|
||||
}
|
||||
if (trState->options.bypassStorageQuota) {
|
||||
tr.flags = tr.flags | CommitTransactionRequest::FLAG_BYPASS_STORAGE_QUOTA;
|
||||
}
|
||||
if (trState->options.reportConflictingKeys) {
|
||||
tr.transaction.report_conflicting_keys = true;
|
||||
}
|
||||
|
@ -6972,6 +6976,10 @@ void Transaction::setOption(FDBTransactionOptions::Option option, Optional<Strin
|
|||
trState->options.rawAccess = true;
|
||||
break;
|
||||
|
||||
case FDBTransactionOptions::BYPASS_STORAGE_QUOTA:
|
||||
trState->options.bypassStorageQuota = true;
|
||||
break;
|
||||
|
||||
case FDBTransactionOptions::AUTHORIZATION_TOKEN:
|
||||
if (value.present())
|
||||
trState->authToken = Standalone<StringRef>(value.get());
|
||||
|
|
|
@ -196,10 +196,11 @@ struct CommitID {
|
|||
|
||||
struct CommitTransactionRequest : TimedRequest {
|
||||
constexpr static FileIdentifier file_identifier = 93948;
|
||||
enum { FLAG_IS_LOCK_AWARE = 0x1, FLAG_FIRST_IN_BATCH = 0x2 };
|
||||
enum { FLAG_IS_LOCK_AWARE = 0x1, FLAG_FIRST_IN_BATCH = 0x2, FLAG_BYPASS_STORAGE_QUOTA = 0x4 };
|
||||
|
||||
bool isLockAware() const { return (flags & FLAG_IS_LOCK_AWARE) != 0; }
|
||||
bool firstInBatch() const { return (flags & FLAG_FIRST_IN_BATCH) != 0; }
|
||||
bool bypassStorageQuota() const { return (flags & FLAG_BYPASS_STORAGE_QUOTA) != 0; }
|
||||
|
||||
Arena arena;
|
||||
SpanContext spanContext;
|
||||
|
|
|
@ -161,6 +161,7 @@ struct TransactionOptions {
|
|||
bool useGrvCache : 1;
|
||||
bool skipGrvCache : 1;
|
||||
bool rawAccess : 1;
|
||||
bool bypassStorageQuota : 1;
|
||||
|
||||
TransactionPriority priority;
|
||||
|
||||
|
|
|
@ -253,6 +253,8 @@ description is not currently required but encouraged.
|
|||
description="Allows this transaction to read system keys (those that start with the byte 0xFF). Implies raw_access."/>
|
||||
<Option name="raw_access" code="303"
|
||||
description="Allows this transaction to access the raw key-space when tenant mode is on."/>
|
||||
<Option name="bypass_storage_quota" code="304"
|
||||
description="Allows this transaction to bypass storage quota enforcement. Should only be used for transactions that directly or indirectly decrease the size of the tenant group's data."/>
|
||||
<Option name="debug_dump" code="400"
|
||||
hidden="true" />
|
||||
<Option name="debug_retry_logging" code="401" paramType="String" paramDescription="Optional transaction name" />
|
||||
|
|
|
@ -414,7 +414,7 @@ ACTOR Future<Void> commitBatcher(ProxyCommitData* commitData,
|
|||
}
|
||||
|
||||
Optional<TenantNameRef> const& tenantName = req.tenantInfo.name;
|
||||
if (SERVER_KNOBS->STORAGE_QUOTA_ENABLED && tenantName.present() &&
|
||||
if (SERVER_KNOBS->STORAGE_QUOTA_ENABLED && !req.bypassStorageQuota() && tenantName.present() &&
|
||||
commitData->tenantsOverStorageQuota.count(tenantName.get()) > 0) {
|
||||
req.reply.sendError(storage_quota_exceeded());
|
||||
continue;
|
||||
|
|
|
@ -92,11 +92,15 @@ struct StorageQuotaWorkload : TestWorkload {
|
|||
}
|
||||
|
||||
// Check that writes to both the tenants are rejected when the group is over quota.
|
||||
state bool rejected1 = wait(tryWrite(self, cx, self->tenant, /*expectOk=*/false));
|
||||
state bool rejected1 = wait(tryWrite(self, cx, self->tenant, /*bypassQuota=*/false, /*expectOk=*/false));
|
||||
ASSERT(rejected1);
|
||||
state bool rejected2 = wait(tryWrite(self, cx, self->emptyTenant, /*expectOk=*/false));
|
||||
state bool rejected2 = wait(tryWrite(self, cx, self->emptyTenant, /*bypassQuota=*/false, /*expectOk=*/false));
|
||||
ASSERT(rejected2);
|
||||
|
||||
// Check that transaction is able to commit if we use the FDBTransactionOptions to bypass quota.
|
||||
state bool bypassed = wait(tryWrite(self, cx, self->tenant, /*bypassQuota=*/true, /*expectOk=*/true));
|
||||
ASSERT(bypassed);
|
||||
|
||||
// Increase the quota or clear the quota. Check that writes to both the tenants are now able to commit.
|
||||
if (deterministicRandom()->coinflip()) {
|
||||
quota = size * 2;
|
||||
|
@ -104,9 +108,9 @@ struct StorageQuotaWorkload : TestWorkload {
|
|||
} else {
|
||||
wait(clearStorageQuotaHelper(cx, self->group));
|
||||
}
|
||||
state bool committed1 = wait(tryWrite(self, cx, self->tenant, /*expectOk=*/true));
|
||||
state bool committed1 = wait(tryWrite(self, cx, self->tenant, /*bypassQuota=*/false, /*expectOk=*/true));
|
||||
ASSERT(committed1);
|
||||
state bool committed2 = wait(tryWrite(self, cx, self->emptyTenant, /*expectOk=*/true));
|
||||
state bool committed2 = wait(tryWrite(self, cx, self->emptyTenant, /*bypassQuota=*/false, /*expectOk=*/true));
|
||||
ASSERT(committed2);
|
||||
|
||||
return Void();
|
||||
|
@ -173,13 +177,20 @@ struct StorageQuotaWorkload : TestWorkload {
|
|||
}
|
||||
}
|
||||
|
||||
ACTOR static Future<bool> tryWrite(StorageQuotaWorkload* self, Database cx, TenantName tenant, bool expectOk) {
|
||||
ACTOR static Future<bool> tryWrite(StorageQuotaWorkload* self,
|
||||
Database cx,
|
||||
TenantName tenant,
|
||||
bool bypassQuota,
|
||||
bool expectOk) {
|
||||
state int i;
|
||||
// Retry the transaction a few times if needed; this allows us wait for a while for all
|
||||
// the storage usage and quota related monitors to fetch and propagate the latest information
|
||||
// about the tenants that are over storage quota.
|
||||
for (i = 0; i < 10; i++) {
|
||||
state Transaction tr(cx, tenant);
|
||||
if (bypassQuota) {
|
||||
tr.setOption(FDBTransactionOptions::BYPASS_STORAGE_QUOTA);
|
||||
}
|
||||
loop {
|
||||
try {
|
||||
Standalone<KeyValueRef> kv =
|
||||
|
|
Loading…
Reference in New Issue