Add IdempotencyId struct
This commit is contained in:
parent
332ee27ec8
commit
329a2724ff
|
@ -0,0 +1,32 @@
|
|||
#include "fdbclient/IdempotencyId.h"
|
||||
#include "flow/UnitTest.h"
|
||||
|
||||
void forceLinkIdempotencyIdTests() {}
|
||||
|
||||
TEST_CASE("/fdbclient/IdempotencyId/basic") {
|
||||
Arena arena;
|
||||
std::unordered_set<IdempotencyId> idSet;
|
||||
std::vector<IdempotencyId> idVector;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
UID id = deterministicRandom()->randomUniqueID();
|
||||
idVector.emplace_back(id);
|
||||
idSet.emplace(id);
|
||||
}
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
int length = deterministicRandom()->randomInt(16, 256);
|
||||
StringRef id = makeString(length, arena);
|
||||
deterministicRandom()->randomBytes(mutateString(id), length);
|
||||
idVector.emplace_back(id);
|
||||
idSet.emplace(id);
|
||||
}
|
||||
|
||||
ASSERT(idSet.size() == idVector.size());
|
||||
for (const auto& id : idVector) {
|
||||
ASSERT(idSet.find(id) != idSet.end());
|
||||
idSet.erase(id);
|
||||
ASSERT(idSet.find(id) == idSet.end());
|
||||
}
|
||||
ASSERT(idSet.size() == 0);
|
||||
|
||||
return Void();
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* IdempotencyId.h
|
||||
*
|
||||
* This source file is part of the FoundationDB open source project
|
||||
*
|
||||
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "flow/Arena.h"
|
||||
#include "flow/IRandom.h"
|
||||
|
||||
struct IdempotencyId {
|
||||
explicit IdempotencyId(UID id) : IdempotencyId(StringRef(reinterpret_cast<const uint8_t*>(&id), sizeof(UID))) {}
|
||||
explicit IdempotencyId(StringRef id) {
|
||||
ASSERT(id.size() >= 16);
|
||||
ASSERT(id.size() < 256);
|
||||
if (id.size() == 16 &&
|
||||
/* If it's 16 bytes but first < 256 we still need to use an indirection to avoid ambiguity. */
|
||||
reinterpret_cast<const uint64_t*>(id.begin())[0] >= 256) {
|
||||
first = reinterpret_cast<const uint64_t*>(id.begin())[0];
|
||||
second.id = reinterpret_cast<const uint64_t*>(id.begin())[1];
|
||||
} else {
|
||||
first = id.size();
|
||||
second.ptr = new uint8_t[id.size()];
|
||||
memcpy(second.ptr, id.begin(), id.size());
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const IdempotencyId& other) const { return asStringRef() == other.asStringRef(); }
|
||||
|
||||
IdempotencyId(IdempotencyId&& other) { *this = std::move(other); }
|
||||
|
||||
IdempotencyId& operator=(IdempotencyId&& other) {
|
||||
first = other.first;
|
||||
if (other.indirect()) {
|
||||
second.ptr = other.second.ptr;
|
||||
other.first = 256; // Make sure other no longer thinks it has ownership. Anything >= 256 would do.
|
||||
} else {
|
||||
second.id = other.second.id;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~IdempotencyId() {
|
||||
if (indirect()) {
|
||||
delete second.ptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool indirect() const { return first < 256; }
|
||||
StringRef asStringRef() const {
|
||||
if (indirect()) {
|
||||
return StringRef(reinterpret_cast<const uint8_t*>(second.ptr), first);
|
||||
} else {
|
||||
return StringRef(reinterpret_cast<const uint8_t*>(this), sizeof(*this));
|
||||
}
|
||||
}
|
||||
uint64_t first;
|
||||
union {
|
||||
uint64_t id;
|
||||
uint8_t* ptr;
|
||||
} second; // If first < 256, then ptr is valid. Otherwise id is valid.
|
||||
friend std::hash<IdempotencyId>;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<IdempotencyId> {
|
||||
std::size_t operator()(const IdempotencyId& id) const { return std::hash<StringRef>{}(id.asStringRef()); }
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
// The plan is to use this as a key in a potentially large hashtable, so it should be compact.
|
||||
static_assert(sizeof(IdempotencyId) == 16);
|
|
@ -43,6 +43,7 @@ void forceLinkRESTUtilsTests();
|
|||
void forceLinkRESTKmsConnectorTest();
|
||||
void forceLinkCompressionUtilsTest();
|
||||
void forceLinkAtomicTests();
|
||||
void forceLinkIdempotencyIdTests();
|
||||
|
||||
struct UnitTestWorkload : TestWorkload {
|
||||
bool enabled;
|
||||
|
@ -100,6 +101,7 @@ struct UnitTestWorkload : TestWorkload {
|
|||
forceLinkRESTKmsConnectorTest();
|
||||
forceLinkCompressionUtilsTest();
|
||||
forceLinkAtomicTests();
|
||||
forceLinkIdempotencyIdTests();
|
||||
}
|
||||
|
||||
std::string description() const override { return "UnitTests"; }
|
||||
|
|
Loading…
Reference in New Issue