22 Commits

Author SHA1 Message Date
60cb274a15 Update corpus
All checks were successful
Tests / Clang total: 1533, passed: 1533
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1533, passed: 1533
Tests / Release [gcc] total: 1533, passed: 1533
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |2|0|2|0|:zzz:
Tests / Release [gcc,aarch64] total: 1144, passed: 1144
Tests / Coverage total: 1151, passed: 1151
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.71% (1606/1627) * Branch Coverage: 65.63% (1472/2243) * Complexity Density: 0.00 * Lines of Code: 1627 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-07-10 18:49:41 -07:00
687bc9c935 Explicitly say that begin must be < end in interface 2024-07-10 17:05:08 -07:00
d50bb8bc80 Add missing header
All checks were successful
Tests / Clang total: 1337, passed: 1337
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1337, passed: 1337
Tests / Release [gcc] total: 1337, passed: 1337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |2|0|2|0|:zzz:
Tests / Release [gcc,aarch64] total: 997, passed: 997
Tests / Coverage total: 1004, passed: 1004
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 97.48% (1586/1627) * Branch Coverage: 63.66% (1428/2243) * Complexity Density: 0.00 * Lines of Code: 1627 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-07-10 16:59:31 -07:00
f19b403f19 Remove "writes are canonical" precondition from addWrites
Some checks failed
weaselab/conflict-set/pipeline/head There was a failure building this commit
2024-07-10 16:42:53 -07:00
34cd210907 Update README benchmarks
All checks were successful
Tests / Clang total: 1337, passed: 1337
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1337, passed: 1337
Tests / Release [gcc] total: 1337, passed: 1337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 997, passed: 997
Tests / Coverage total: 1004, passed: 1004
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.71% (1606/1627) * Branch Coverage: 65.58% (1471/2243) * Complexity Density: 0.00 * Lines of Code: 1627 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-07-09 16:06:44 -07:00
1a5da9e899 Bump version
All checks were successful
Tests / Clang total: 1337, passed: 1337
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1337, passed: 1337
Tests / Release [gcc] total: 1337, passed: 1337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 997, passed: 997
Tests / Coverage total: 1004, passed: 1004
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.71% (1606/1627) * Branch Coverage: 65.58% (1471/2243) * Complexity Density: 0.00 * Lines of Code: 1627 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-07-08 16:12:23 -07:00
8ba9b04d8c Remove "32-bit versions" jenkins stage
This is the default now
2024-07-08 15:45:10 -07:00
d895be36d2 Declare dependency on version.txt in Makefile
All checks were successful
Tests / Clang total: 1337, passed: 1337
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1337, passed: 1337
Tests / 32-bit versions total: 1337, passed: 1337
Tests / Release [gcc] total: 1337, passed: 1337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 997, passed: 997
Tests / Coverage total: 1004, passed: 1004
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.71% (1606/1627) * Branch Coverage: 65.58% (1471/2243) * Complexity Density: 0.00 * Lines of Code: 1627 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-07-08 15:41:51 -07:00
65f8462e88 Remove dead code
All checks were successful
Tests / Clang total: 1337, passed: 1337
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1337, passed: 1337
Tests / 32-bit versions total: 1337, passed: 1337
Tests / Release [gcc] total: 1337, passed: 1337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 997, passed: 997
Tests / Coverage total: 1004, passed: 1004
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.71% (1606/1627) * Branch Coverage: 65.58% (1471/2243) * Complexity Density: 0.00 * Lines of Code: 1627 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-07-08 11:14:30 -07:00
46e01af027 Specialize scan16 for Node16 in checkMaxBetweenExclusive
All checks were successful
Tests / Clang total: 1337, passed: 1337
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1337, passed: 1337
Tests / 32-bit versions total: 1337, passed: 1337
Tests / Release [gcc] total: 1337, passed: 1337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 997, passed: 997
Tests / Coverage total: 1004, passed: 1004
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.71% (1606/1627) * Branch Coverage: 65.58% (1471/2243) * Complexity Density: 0.00 * Lines of Code: 1627 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-07-08 11:01:17 -07:00
c9d0d72684 Remove some branches for Node3 in checkMaxBetweenExclusive
All checks were successful
Tests / Clang total: 1337, passed: 1337
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1337, passed: 1337
Tests / 32-bit versions total: 1337, passed: 1337
Tests / Release [gcc] total: 1337, passed: 1337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 997, passed: 997
Tests / Coverage total: 1004, passed: 1004
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.76% (1599/1619) * Branch Coverage: 65.86% (1466/2226) * Complexity Density: 0.00 * Lines of Code: 1619 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-07-07 20:45:20 -07:00
9046dc5a8f Only switch on type once in checkMaxBetweenExclusive
All checks were successful
Tests / Clang total: 1337, passed: 1337
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1337, passed: 1337
Tests / 32-bit versions total: 1337, passed: 1337
Tests / Release [gcc] total: 1337, passed: 1337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 997, passed: 997
Tests / Coverage total: 1004, passed: 1004
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.77% (1602/1622) * Branch Coverage: 65.86% (1468/2229) * Complexity Density: 0.00 * Lines of Code: 1622 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-07-07 17:28:45 -07:00
e2927bf0fa Simplify condition for TooOld in check
All checks were successful
Tests / Clang total: 1337, passed: 1337
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1337, passed: 1337
Tests / 32-bit versions total: 1337, passed: 1337
Tests / Release [gcc] total: 1337, passed: 1337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 997, passed: 997
Tests / Coverage total: 1004, passed: 1004
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.74% (1570/1590) * Branch Coverage: 65.35% (1422/2176) * Complexity Density: 0.00 * Lines of Code: 1590 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-07-03 16:39:22 -07:00
75a2b8d06c Remove bogus assert
All checks were successful
Tests / Clang total: 1337, passed: 1337
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1337, passed: 1337
Tests / 32-bit versions total: 1337, passed: 1337
Tests / Release [gcc] total: 1337, passed: 1337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 997, passed: 997
Tests / Coverage total: 1004, passed: 1004
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.74% (1572/1592) * Branch Coverage: 65.33% (1421/2175) * Complexity Density: 0.00 * Lines of Code: 1592 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
It's bogus since we mess with oldestVersionFullPrecision in addWrites
2024-07-03 14:47:50 -07:00
76df63a9d7 Allow writeVersion, oldestVersion, and readVersion to span 2e9
Some checks failed
Tests / Clang total: 1337, passed: 1337
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1337, passed: 1337
Tests / 32-bit versions total: 1337, passed: 1337
Tests / Release [gcc] total: 1337, passed: 1337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 997, passed: 997
Tests / Coverage total: 1004, failed: 86, passed: 918
weaselab/conflict-set/pipeline/head There was a failure building this commit
2024-07-03 14:19:50 -07:00
9c5b38b09a Revert setOldestVersion interface change 2024-07-03 11:27:09 -07:00
7142dab7ae Update c api documentation for ConflictSet_setOldestVersion 2024-07-03 10:53:45 -07:00
3db3d975fc Interface change! Allow decreasing setOldestVersion
All checks were successful
Tests / Clang total: 1305, passed: 1305
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1305, passed: 1305
Tests / 32-bit versions total: 1305, passed: 1305
Tests / Release [gcc] total: 1305, passed: 1305
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 973, passed: 973
Tests / Coverage total: 980, passed: 980
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.74% (1572/1592) * Branch Coverage: 65.29% (1420/2175) * Complexity Density: 0.00% * Lines of Code: 1592 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-07-03 10:31:57 -07:00
982b31af34 Explicitly convert uint32x4_t to int32x4_t
Some checks failed
Tests / Clang total: 1305, passed: 1305
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1305, passed: 1305
Tests / 32-bit versions total: 1305, passed: 1305
Tests / Release [gcc] total: 1305, passed: 1305
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 973, passed: 973
Tests / Coverage total: 980, failed: 82, passed: 898
weaselab/conflict-set/pipeline/head There was a failure building this commit
2024-07-03 10:01:00 -07:00
cc716ef16b Attempt to fix memory leak
Some checks failed
Tests / Clang total: 1305, passed: 1305
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1305, passed: 1305
Tests / 32-bit versions total: 1305, passed: 1305
Tests / Release [gcc] total: 1305, passed: 1305
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
weaselab/conflict-set/pipeline/head There was a failure building this commit
2024-07-03 09:48:02 -07:00
88bcc7b75c Update corpus
Some checks failed
Tests / Clang total: 1305, failed: 47, passed: 1258
Tests / SIMD fallback total: 1305, failed: 47, passed: 1258
Tests / 32-bit versions total: 1305, failed: 47, passed: 1258
Tests / Release [gcc] total: 1305, failed: 47, passed: 1258
weaselab/conflict-set/pipeline/head There was a failure building this commit
2024-07-03 09:36:03 -07:00
3e6be6bd83 Allow write version to jump by more than 2e9 2024-07-03 09:07:09 -07:00
830 changed files with 455 additions and 121 deletions

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.18) cmake_minimum_required(VERSION 3.18)
project( project(
conflict-set conflict-set
VERSION 0.0.7 VERSION 0.0.8
DESCRIPTION DESCRIPTION
"A data structure for optimistic concurrency control on ranges of bitwise-lexicographically-ordered keys." "A data structure for optimistic concurrency control on ranges of bitwise-lexicographically-ordered keys."
HOMEPAGE_URL "https://git.weaselab.dev/weaselab/conflict-set" HOMEPAGE_URL "https://git.weaselab.dev/weaselab/conflict-set"

View File

@@ -606,6 +606,14 @@ template <class T> struct BoundedFreeListAllocator {
VALGRIND_MAKE_MEM_NOACCESS(freeList, sizeof(T) + p->partialKeyCapacity); VALGRIND_MAKE_MEM_NOACCESS(freeList, sizeof(T) + p->partialKeyCapacity);
} }
BoundedFreeListAllocator() = default;
BoundedFreeListAllocator(const BoundedFreeListAllocator &) = delete;
BoundedFreeListAllocator &
operator=(const BoundedFreeListAllocator &) = delete;
BoundedFreeListAllocator(BoundedFreeListAllocator &&) = delete;
BoundedFreeListAllocator &operator=(BoundedFreeListAllocator &&) = delete;
~BoundedFreeListAllocator() { ~BoundedFreeListAllocator() {
for (void *iter = freeList; iter != nullptr;) { for (void *iter = freeList; iter != nullptr;) {
VALGRIND_MAKE_MEM_DEFINED(iter, sizeof(Node)); VALGRIND_MAKE_MEM_DEFINED(iter, sizeof(Node));
@@ -1875,7 +1883,8 @@ bool scan16(const InternalVersionT *vs, const uint8_t *is, int begin, int end,
uint16x4_t conflicting[4]; uint16x4_t conflicting[4];
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
conflicting[i] = vmovn_u32(vcgtq_s32(vsubq_u32(w4[i], rvVec), z)); conflicting[i] =
vmovn_u32(vcgtq_s32(vreinterpretq_s32_u32(vsubq_u32(w4[i], rvVec)), z));
} }
auto combined = auto combined =
vcombine_u8(vmovn_u16(vcombine_u16(conflicting[0], conflicting[1])), vcombine_u8(vmovn_u16(vcombine_u16(conflicting[0], conflicting[1])),
@@ -1944,7 +1953,8 @@ scan16(const InternalVersionT *vs, int begin, int end,
uint16x4_t conflicting[4]; uint16x4_t conflicting[4];
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
conflicting[i] = vmovn_u32(vcgtq_s32(vsubq_u32(w4[i], rvVec), z)); conflicting[i] =
vmovn_u32(vcgtq_s32(vreinterpretq_s32_u32(vsubq_u32(w4[i], rvVec)), z));
} }
auto combined = auto combined =
vcombine_u8(vmovn_u16(vcombine_u16(conflicting[0], conflicting[1])), vcombine_u8(vmovn_u16(vcombine_u16(conflicting[0], conflicting[1])),
@@ -1991,55 +2001,163 @@ bool checkMaxBetweenExclusive(Node *n, int begin, int end,
assert(!(begin == -1 && end == 256)); assert(!(begin == -1 && end == 256));
{
int c = getChildGeq(n, begin + 1);
if (c >= 0 && c < end) {
auto *child = getChildExists(n, c);
if (child->entryPresent) {
if (!(child->entry.rangeVersion <= readVersion)) {
return false;
};
}
begin = c;
} else {
return true;
}
}
// [begin, end) is now the half-open interval of children we're interested in.
assert(begin < end);
switch (n->getType()) { switch (n->getType()) {
case Type_Node0: // GCOVR_EXCL_LINE case Type_Node0:
// We would have returned above, after not finding a child return true;
__builtin_unreachable(); // GCOVR_EXCL_LINE
case Type_Node3: { case Type_Node3: {
auto *self = static_cast<Node3 *>(n); auto *self = static_cast<Node3 *>(n);
++begin;
const unsigned shiftUpperBound = end - begin; const unsigned shiftUpperBound = end - begin;
const unsigned shiftAmount = begin; const unsigned shiftAmount = begin;
auto inBounds = [&](unsigned c) { auto inBounds = [&](unsigned c) {
return c - shiftAmount < shiftUpperBound; return c - shiftAmount < shiftUpperBound;
}; };
uint32_t compared = 0;
for (int i = 0; i < Node3::kMaxNodes; ++i) {
compared |= (self->childMaxVersion[i] > readVersion) << i;
}
uint32_t mask = 0; uint32_t mask = 0;
for (int i = 0; i < Node3::kMaxNodes; ++i) { for (int i = 0; i < Node3::kMaxNodes; ++i) {
mask |= inBounds(self->index[i]) << i; mask |= inBounds(self->index[i]) << i;
} }
return !(compared & mask); mask &= (1 << self->numChildren) - 1;
if (!mask) {
return true;
}
auto *child = self->children[__builtin_ctz(mask)];
const bool firstRangeOk =
!child->entryPresent || child->entry.rangeVersion <= readVersion;
uint32_t compared = 0;
for (int i = 0; i < Node3::kMaxNodes; ++i) {
compared |= (self->childMaxVersion[i] > readVersion) << i;
}
return !(compared & mask) && firstRangeOk;
} }
case Type_Node16: { case Type_Node16: {
auto *self = static_cast<Node16 *>(n); auto *self = static_cast<Node16 *>(n);
return scan16<kAVX512>(self->childMaxVersion, self->index, begin, end, ++begin;
readVersion);
assert(begin <= end);
assert(end - begin < 256);
#ifdef HAS_ARM_NEON
uint8x16_t indices;
memcpy(&indices, self->index, 16);
// 0xff for each in bounds
auto results =
vcltq_u8(vsubq_u8(indices, vdupq_n_u8(begin)), vdupq_n_u8(end - begin));
// 0xf for each 0xff
uint64_t mask = vget_lane_u64(
vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(results), 4)), 0);
mask &= self->numChildren == 16
? uint64_t(-1)
: (uint64_t(1) << (self->numChildren << 2)) - 1;
if (!mask) {
return true;
}
auto *child = self->children[__builtin_ctzll(mask) >> 2];
const bool firstRangeOk =
!child->entryPresent || child->entry.rangeVersion <= readVersion;
uint32x4_t w4[4];
memcpy(w4, self->childMaxVersion, sizeof(w4));
uint32_t rv;
memcpy(&rv, &readVersion, sizeof(rv));
const auto rvVec = vdupq_n_u32(rv);
int32x4_t z;
memset(&z, 0, sizeof(z));
uint16x4_t conflicting[4];
for (int i = 0; i < 4; ++i) {
conflicting[i] = vmovn_u32(
vcgtq_s32(vreinterpretq_s32_u32(vsubq_u32(w4[i], rvVec)), z));
}
auto combined =
vcombine_u8(vmovn_u16(vcombine_u16(conflicting[0], conflicting[1])),
vmovn_u16(vcombine_u16(conflicting[2], conflicting[3])));
uint64_t compared = vget_lane_u64(
vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(combined), 4)), 0);
return !(compared & mask) && firstRangeOk;
#elif defined(HAS_AVX)
__m128i indices;
memcpy(&indices, self->index, 16);
indices = _mm_sub_epi8(indices, _mm_set1_epi8(begin));
uint32_t mask =
0xffff &
~_mm_movemask_epi8(_mm_cmpeq_epi8(
indices, _mm_max_epu8(indices, _mm_set1_epi8(end - begin))));
mask &= (1 << self->numChildren) - 1;
if (!mask) {
return true;
}
auto *child = self->children[__builtin_ctz(mask)];
const bool firstRangeOk =
!child->entryPresent || child->entry.rangeVersion <= readVersion;
uint32_t compared = 0;
if constexpr (kAVX512) {
compared = compare16_32bit_avx512(self->childMaxVersion, readVersion);
} else {
compared = compare16_32bit(self->childMaxVersion, readVersion);
}
return !(compared & mask) && firstRangeOk;
#else
const unsigned shiftUpperBound = end - begin;
const unsigned shiftAmount = begin;
auto inBounds = [&](unsigned c) {
return c - shiftAmount < shiftUpperBound;
};
uint32_t mask = 0;
for (int i = 0; i < 16; ++i) {
mask |= inBounds(self->index[i]) << i;
}
mask &= (1 << self->numChildren) - 1;
if (!mask) {
return true;
}
auto *child = self->children[__builtin_ctz(mask)];
const bool firstRangeOk =
!child->entryPresent || child->entry.rangeVersion <= readVersion;
uint32_t compared = 0;
for (int i = 0; i < 16; ++i) {
compared |= (self->childMaxVersion[i] > readVersion) << i;
}
return !(compared & mask) && firstRangeOk;
#endif
} }
case Type_Node48: { case Type_Node48: {
auto *self = static_cast<Node48 *>(n); auto *self = static_cast<Node48 *>(n);
{
int c = self->bitSet.firstSetGeq(begin + 1);
if (c >= 0 && c < end) {
auto *child = self->children[self->index[c]];
if (child->entryPresent) {
if (!(child->entry.rangeVersion <= readVersion)) {
return false;
};
}
begin = c;
} else {
return true;
}
// [begin, end) is now the half-open interval of children we're interested
// in.
assert(begin < end);
}
// Check all pages // Check all pages
static_assert(Node48::kMaxOfMaxPageSize == 16); static_assert(Node48::kMaxOfMaxPageSize == 16);
for (int i = 0; i < Node48::kMaxOfMaxTotalPages; ++i) { for (int i = 0; i < Node48::kMaxOfMaxTotalPages; ++i) {
@@ -2057,6 +2175,25 @@ bool checkMaxBetweenExclusive(Node *n, int begin, int end,
case Type_Node256: { case Type_Node256: {
static_assert(Node256::kMaxOfMaxTotalPages == 16); static_assert(Node256::kMaxOfMaxTotalPages == 16);
auto *self = static_cast<Node256 *>(n); auto *self = static_cast<Node256 *>(n);
{
int c = self->bitSet.firstSetGeq(begin + 1);
if (c >= 0 && c < end) {
auto *child = self->children[c];
if (child->entryPresent) {
if (!(child->entry.rangeVersion <= readVersion)) {
return false;
};
}
begin = c;
} else {
return true;
}
// [begin, end) is now the half-open interval of children we're interested
// in.
assert(begin < end);
}
const int firstPage = begin >> Node256::kMaxOfMaxShift; const int firstPage = begin >> Node256::kMaxOfMaxShift;
const int lastPage = (end - 1) >> Node256::kMaxOfMaxShift; const int lastPage = (end - 1) >> Node256::kMaxOfMaxShift;
// Check the only page if there's only one // Check the only page if there's only one
@@ -2874,11 +3011,10 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
const auto &r = reads[i]; const auto &r = reads[i];
auto begin = std::span<const uint8_t>(r.begin.p, r.begin.len); auto begin = std::span<const uint8_t>(r.begin.p, r.begin.len);
auto end = std::span<const uint8_t>(r.end.p, r.end.len); auto end = std::span<const uint8_t>(r.end.p, r.end.len);
assert(oldestVersionFullPrecision >=
newestVersionFullPrecision - kNominalVersionWindow);
result[i] = result[i] =
reads[i].readVersion < oldestVersionFullPrecision || reads[i].readVersion < oldestVersionFullPrecision ? TooOld
reads[i].readVersion <
newestVersionFullPrecision - kNominalVersionWindow
? TooOld
: (end.size() > 0 : (end.size() > 0
? checkRangeRead(root, begin, end, ? checkRangeRead(root, begin, end,
InternalVersionT(reads[i].readVersion), this) InternalVersionT(reads[i].readVersion), this)
@@ -2892,8 +3028,10 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
void addWrites(const WriteRange *writes, int count, int64_t writeVersion) { void addWrites(const WriteRange *writes, int count, int64_t writeVersion) {
assert(writeVersion >= newestVersionFullPrecision); assert(writeVersion >= newestVersionFullPrecision);
// TODO allow this condition if (writeVersion > newestVersionFullPrecision + kNominalVersionWindow) {
assert(writeVersion < newestVersionFullPrecision + kNominalVersionWindow); destroyTree(root);
init(writeVersion - kNominalVersionWindow);
}
newestVersionFullPrecision = writeVersion; newestVersionFullPrecision = writeVersion;
setOldestVersion( setOldestVersion(
@@ -2985,14 +3123,19 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
keyUpdates = gcScanStep(keyUpdates); keyUpdates = gcScanStep(keyUpdates);
} }
explicit Impl(int64_t oldestVersion) int64_t getBytes() const { return totalBytes; }
: oldestVersion(oldestVersion), oldestVersionFullPrecision(oldestVersion),
oldestExtantVersion(oldestVersion), void init(int64_t oldestVersion) {
oldestVersionAtGcBegin(oldestVersion), this->oldestVersion = InternalVersionT(oldestVersion);
newestVersionFullPrecision(oldestVersion) { oldestVersionFullPrecision = oldestExtantVersion = oldestVersionAtGcBegin =
#if DEBUG_VERBOSE newestVersionFullPrecision = oldestVersion;
fprintf(stderr, "radix_tree: create\n");
#endif allocators.~NodeAllocators();
new (&allocators) NodeAllocators();
removalKeyArena = Arena{};
removalKey = {};
keyUpdates = 10;
// Insert "" // Insert ""
root = allocators.node0.allocate(0); root = allocators.node0.allocate(0);
@@ -3009,26 +3152,22 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
root->entry.rangeVersion = this->oldestVersion; root->entry.rangeVersion = this->oldestVersion;
InternalVersionT::zero = this->oldestVersion; InternalVersionT::zero = this->oldestVersion;
// Intentionally not resetting totalBytes
} }
~Impl() {
#if DEBUG_VERBOSE explicit Impl(int64_t oldestVersion) { init(oldestVersion); }
fprintf(stderr, "radix_tree: destroy\n"); ~Impl() { destroyTree(root); }
#endif
destroyTree(root);
}
NodeAllocators allocators; NodeAllocators allocators;
Arena removalKeyArena; Arena removalKeyArena;
std::span<const uint8_t> removalKey; std::span<const uint8_t> removalKey;
int64_t keyUpdates = 10; int64_t keyUpdates;
Node *root; Node *root;
InternalVersionT rootMaxVersion; InternalVersionT rootMaxVersion;
InternalVersionT oldestVersion; InternalVersionT oldestVersion;
// TODO this doesn't fully mitigate the 32-bit precision issue, since we still
// need to make sure we clean up versions in the tree before they fall out of
// the `kMaxCorrectVersionWindow` window.
int64_t oldestVersionFullPrecision; int64_t oldestVersionFullPrecision;
int64_t oldestExtantVersion; int64_t oldestExtantVersion;
int64_t oldestVersionAtGcBegin; int64_t oldestVersionAtGcBegin;
@@ -3163,7 +3302,7 @@ void internal_destroy(ConflictSet::Impl *impl) {
safe_free(impl, sizeof(ConflictSet::Impl)); safe_free(impl, sizeof(ConflictSet::Impl));
} }
int64_t internal_getBytes(ConflictSet::Impl *impl) { return impl->totalBytes; } int64_t internal_getBytes(ConflictSet::Impl *impl) { return impl->getBytes(); }
// ==================== END IMPLEMENTATION ==================== // ==================== END IMPLEMENTATION ====================
@@ -3191,11 +3330,7 @@ Iterator firstGeqLogical(Node *n, const std::span<const uint8_t> key) {
} else { } else {
n = nextSibling(n); n = nextSibling(n);
if (n == nullptr) { if (n == nullptr) {
// This line is genuinely unreachable from any entry point of the return {nullptr, 1};
// final library, since we can't remove a key without introducing a
// key after it, and the only production caller of firstGeq is for
// resuming the setOldestVersion scan.
return {nullptr, 1}; // GCOVR_EXCL_LINE
} }
goto downLeftSpine; goto downLeftSpine;
} }
@@ -3476,8 +3611,8 @@ void checkVersionsGeqOldestExtant(Node *n,
assert(m >= oldestExtantVersion); assert(m >= oldestExtantVersion);
} }
} break; } break;
default: // GCOVR_EXCL_LINE default:
__builtin_unreachable(); // GCOVR_EXCL_LINE abort();
} }
} }

View File

@@ -518,7 +518,7 @@ struct ReferenceImpl {
} }
void setOldestVersion(int64_t oldestVersion) { void setOldestVersion(int64_t oldestVersion) {
assert(oldestVersion >= oldestVersion); assert(oldestVersion >= this->oldestVersion);
this->oldestVersion = oldestVersion; this->oldestVersion = oldestVersion;
} }
@@ -583,8 +583,8 @@ template <class ConflictSetImpl> struct TestDriver {
explicit TestDriver(const uint8_t *data, size_t size) explicit TestDriver(const uint8_t *data, size_t size)
: arbitrary({data, size}) {} : arbitrary({data, size}) {}
int64_t oldestVersion = 0; int64_t oldestVersion = arbitrary.next();
int64_t writeVersion = 0; int64_t writeVersion = oldestVersion;
ConflictSetImpl cs{oldestVersion}; ConflictSetImpl cs{oldestVersion};
ReferenceImpl refImpl{oldestVersion}; ReferenceImpl refImpl{oldestVersion};
@@ -598,6 +598,7 @@ template <class ConflictSetImpl> struct TestDriver {
// Call until it returns true, for "done". Check internal invariants etc // Call until it returns true, for "done". Check internal invariants etc
// between calls to next. // between calls to next.
bool next() { bool next() {
assert(cs.getBytes() >= 0);
if (!arbitrary.hasEntropy()) { if (!arbitrary.hasEntropy()) {
return true; return true;
} }
@@ -605,7 +606,8 @@ template <class ConflictSetImpl> struct TestDriver {
{ {
int numPointWrites = arbitrary.bounded(100); int numPointWrites = arbitrary.bounded(100);
int numRangeWrites = arbitrary.bounded(100); int numRangeWrites = arbitrary.bounded(100);
int64_t v = (writeVersion += arbitrary.bounded(2e9)); int64_t v = (writeVersion += arbitrary.bounded(10) ? arbitrary.bounded(10)
: arbitrary.next());
auto *writes = auto *writes =
new (arena) ConflictSet::WriteRange[numPointWrites + numRangeWrites]; new (arena) ConflictSet::WriteRange[numPointWrites + numRangeWrites];
auto keys = set<std::string_view>(arena); auto keys = set<std::string_view>(arena);
@@ -662,21 +664,64 @@ template <class ConflictSetImpl> struct TestDriver {
fprintf(stderr, "Write @ %" PRId64 "\n", v); fprintf(stderr, "Write @ %" PRId64 "\n", v);
#endif #endif
// Test non-canonical writes
if (numPointWrites > 0) {
int overlaps = arbitrary.bounded(numPointWrites);
for (int i = 0; i < numPointWrites + numRangeWrites && overlaps > 0;
++i) {
if (writes[i].end.len == 0) {
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen);
auto *begin = new (arena) uint8_t[keyLen];
memset(begin, prefixByte, prefixLen);
arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen);
writes[i].end.len = keyLen;
writes[i].end.p = begin;
auto c =
std::span<const uint8_t>(writes[i].begin.p,
writes[i].begin.len) <=>
std::span<const uint8_t>(writes[i].end.p, writes[i].end.len);
if (c > 0) {
using std::swap;
swap(writes[i].begin, writes[i].end);
} else if (c == 0) {
// It's a point write after all, I guess
writes[i].end.len = 0;
}
--overlaps;
}
}
}
if (arbitrary.bounded(2)) {
// Shuffle writes
for (int i = numPointWrites + numRangeWrites - 1; i > 0; --i) {
int j = arbitrary.bounded(i + 1);
if (i != j) {
using std::swap;
swap(writes[i], writes[j]);
}
}
}
CALLGRIND_START_INSTRUMENTATION; CALLGRIND_START_INSTRUMENTATION;
cs.addWrites(writes, numPointWrites + numRangeWrites, v); cs.addWrites(writes, numPointWrites + numRangeWrites, v);
CALLGRIND_STOP_INSTRUMENTATION; CALLGRIND_STOP_INSTRUMENTATION;
refImpl.addWrites(writes, numPointWrites + numRangeWrites, v); refImpl.addWrites(writes, numPointWrites + numRangeWrites, v);
oldestVersion = oldestVersion +=
std::min(writeVersion - 10, oldestVersion + arbitrary.bounded(10)); arbitrary.bounded(10) ? arbitrary.bounded(10) : arbitrary.next();
oldestVersion = std::min(oldestVersion, writeVersion);
cs.setOldestVersion(oldestVersion); cs.setOldestVersion(oldestVersion);
refImpl.setOldestVersion(oldestVersion); refImpl.setOldestVersion(oldestVersion);
} }
{ {
int numPointReads = arbitrary.bounded(100); int numPointReads = arbitrary.bounded(100);
int numRangeReads = arbitrary.bounded(100); int numRangeReads = arbitrary.bounded(100);
int64_t v = std::max<int64_t>(writeVersion - arbitrary.bounded(10), 0);
int64_t v = std::max<int64_t>(writeVersion - (arbitrary.bounded(10)
? arbitrary.bounded(10)
: arbitrary.next()),
0);
auto *reads = auto *reads =
new (arena) ConflictSet::ReadRange[numPointReads + numRangeReads]; new (arena) ConflictSet::ReadRange[numPointReads + numRangeReads];
auto keys = set<std::string_view>(arena); auto keys = set<std::string_view>(arena);

11
Jenkinsfile vendored
View File

@@ -59,17 +59,6 @@ pipeline {
CleanBuildAndTest("-DUSE_SIMD_FALLBACK=ON") CleanBuildAndTest("-DUSE_SIMD_FALLBACK=ON")
} }
} }
stage('32-bit versions') {
agent {
dockerfile {
args '-v /home/jenkins/ccache:/ccache'
reuseNode true
}
}
steps {
CleanBuildAndTest("-DUSE_32_BIT_VERSIONS=ON")
}
}
stage('Release [gcc]') { stage('Release [gcc]') {
agent { agent {
dockerfile { dockerfile {

View File

@@ -60,27 +60,27 @@ Performance counters:
| ns/op | op/s | err% | total | benchmark | ns/op | op/s | err% | total | benchmark
|--------------------:|--------------------:|--------:|----------:|:---------- |--------------------:|--------------------:|--------:|----------:|:----------
| 256.89 | 3,892,784.92 | 0.3% | 0.01 | `point reads` | 245.99 | 4,065,232.81 | 0.3% | 0.01 | `point reads`
| 272.90 | 3,664,395.04 | 0.2% | 0.01 | `prefix reads` | 265.93 | 3,760,430.49 | 0.2% | 0.01 | `prefix reads`
| 507.22 | 1,971,549.50 | 0.7% | 0.01 | `range reads` | 485.30 | 2,060,569.50 | 0.2% | 0.01 | `range reads`
| 452.66 | 2,209,181.91 | 0.5% | 0.01 | `point writes` | 449.60 | 2,224,195.17 | 0.4% | 0.01 | `point writes`
| 438.09 | 2,282,619.96 | 0.4% | 0.01 | `prefix writes` | 441.76 | 2,263,688.18 | 1.1% | 0.01 | `prefix writes`
| 253.33 | 3,947,420.36 | 2.5% | 0.02 | `range writes` | 245.42 | 4,074,647.54 | 2.4% | 0.02 | `range writes`
| 574.07 | 1,741,936.71 | 0.3% | 0.01 | `monotonic increasing point writes` | 572.80 | 1,745,810.06 | 1.3% | 0.01 | `monotonic increasing point writes`
| 151,562.50 | 6,597.94 | 1.5% | 0.01 | `worst case for radix tree` | 154,819.33 | 6,459.14 | 0.9% | 0.01 | `worst case for radix tree`
## Radix tree (this implementation) ## Radix tree (this implementation)
| ns/op | op/s | err% | total | benchmark | ns/op | op/s | err% | total | benchmark
|--------------------:|--------------------:|--------:|----------:|:---------- |--------------------:|--------------------:|--------:|----------:|:----------
| 19.83 | 50,420,955.28 | 0.1% | 0.01 | `point reads` | 19.17 | 52,163,930.66 | 0.1% | 0.01 | `point reads`
| 55.95 | 17,872,542.40 | 0.5% | 0.01 | `prefix reads` | 23.68 | 42,224,388.21 | 0.7% | 0.01 | `prefix reads`
| 88.28 | 11,327,709.50 | 0.4% | 0.01 | `range reads` | 63.30 | 15,797,506.06 | 0.9% | 0.01 | `range reads`
| 29.15 | 34,309,531.64 | 0.5% | 0.01 | `point writes` | 29.66 | 33,720,994.74 | 0.3% | 0.01 | `point writes`
| 42.36 | 23,607,424.27 | 1.1% | 0.01 | `prefix writes` | 43.50 | 22,987,781.25 | 1.0% | 0.01 | `prefix writes`
| 50.00 | 20,000,000.00 | 0.0% | 0.01 | `range writes` | 50.00 | 20,000,000.00 | 0.8% | 0.01 | `range writes`
| 93.52 | 10,692,413.79 | 3.3% | 0.01 | `monotonic increasing point writes` | 103.25 | 9,684,786.47 | 2.9% | 0.01 | `monotonic increasing point writes`
| 2,388,417.00 | 418.69 | 0.4% | 0.03 | `worst case for radix tree` | 1,181,500.00 | 846.38 | 2.3% | 0.01 | `worst case for radix tree`
# "Real data" test # "Real data" test

View File

@@ -22,6 +22,8 @@
#include "ConflictSet.h" #include "ConflictSet.h"
#include "Internal.h" #include "Internal.h"
#include <algorithm>
#include <span> #include <span>
std::span<const uint8_t> keyAfter(Arena &arena, std::span<const uint8_t> key) { std::span<const uint8_t> keyAfter(Arena &arena, std::span<const uint8_t> key) {
@@ -52,6 +54,135 @@ struct KeyRangeRef {
: begin(begin), end(keyAfter(arena, begin)) {} : begin(begin), end(keyAfter(arena, begin)) {}
}; };
struct KeyInfo {
StringRef key;
bool begin;
bool write;
KeyInfo() = default;
KeyInfo(StringRef key, bool begin, bool write)
: key(key), begin(begin), write(write) {}
};
force_inline int extra_ordering(const KeyInfo &ki) {
return ki.begin * 2 + (ki.write ^ ki.begin);
}
// returns true if done with string
force_inline bool getCharacter(const KeyInfo &ki, int character,
int &outputCharacter) {
// normal case
if (character < ki.key.size()) {
outputCharacter = 5 + ki.key.begin()[character];
return false;
}
// termination
if (character == ki.key.size()) {
outputCharacter = 0;
return false;
}
if (character == ki.key.size() + 1) {
// end/begin+read/write relative sorting
outputCharacter = extra_ordering(ki);
return false;
}
outputCharacter = 0;
return true;
}
bool operator<(const KeyInfo &lhs, const KeyInfo &rhs) {
int i = std::min(lhs.key.size(), rhs.key.size());
int c = memcmp(lhs.key.data(), rhs.key.data(), i);
if (c != 0)
return c < 0;
// Always sort shorter keys before longer keys.
if (lhs.key.size() < rhs.key.size()) {
return true;
}
if (lhs.key.size() > rhs.key.size()) {
return false;
}
// When the keys are the same length, use the extra ordering constraint.
return extra_ordering(lhs) < extra_ordering(rhs);
}
bool operator==(const KeyInfo &lhs, const KeyInfo &rhs) {
return !(lhs < rhs || rhs < lhs);
}
void swapSort(std::vector<KeyInfo> &points, int a, int b) {
if (points[b] < points[a]) {
KeyInfo temp;
temp = points[a];
points[a] = points[b];
points[b] = temp;
}
}
struct SortTask {
int begin;
int size;
int character;
SortTask(int begin, int size, int character)
: begin(begin), size(size), character(character) {}
};
void sortPoints(std::vector<KeyInfo> &points) {
std::vector<SortTask> tasks;
std::vector<KeyInfo> newPoints;
std::vector<int> counts;
tasks.emplace_back(0, points.size(), 0);
while (tasks.size()) {
SortTask st = tasks.back();
tasks.pop_back();
if (st.size < 10) {
std::sort(points.begin() + st.begin, points.begin() + st.begin + st.size);
continue;
}
newPoints.resize(st.size);
counts.assign(256 + 5, 0);
// get counts
int c;
bool allDone = true;
for (int i = st.begin; i < st.begin + st.size; i++) {
allDone &= getCharacter(points[i], st.character, c);
counts[c]++;
}
if (allDone)
continue;
// calculate offsets from counts and build next level of tasks
int total = 0;
for (int i = 0; i < counts.size(); i++) {
int temp = counts[i];
if (temp > 1)
tasks.emplace_back(st.begin + total, temp, st.character + 1);
counts[i] = total;
total += temp;
}
// put in their places
for (int i = st.begin; i < st.begin + st.size; i++) {
getCharacter(points[i], st.character, c);
newPoints[counts[c]++] = points[i];
}
// copy back into original points array
for (int i = 0; i < st.size; i++)
points[st.begin + i] = newPoints[i];
}
}
static thread_local uint32_t g_seed = 0; static thread_local uint32_t g_seed = 0;
static inline int skfastrand() { static inline int skfastrand() {
@@ -602,10 +733,40 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
void addWrites(const ConflictSet::WriteRange *writes, int count, void addWrites(const ConflictSet::WriteRange *writes, int count,
int64_t writeVersion) { int64_t writeVersion) {
auto points = std::vector<KeyInfo>(count * 2);
Arena arena;
for (int r = 0; r < count; r++) {
points.emplace_back(StringRef(writes[r].begin.p, writes[r].begin.len),
true, true);
points.emplace_back(
writes[r].end.len > 0
? StringRef{writes[r].end.p, size_t(writes[r].end.len)}
: keyAfter(arena, points.back().key),
false, true);
}
sortPoints(points);
int activeWriteCount = 0;
std::vector<std::pair<StringRef, StringRef>> combinedWriteConflictRanges;
for (const KeyInfo &point : points) {
if (point.write) {
if (point.begin) {
activeWriteCount++;
if (activeWriteCount == 1)
combinedWriteConflictRanges.emplace_back(point.key, StringRef());
} else /*if (point.end)*/ {
activeWriteCount--;
if (activeWriteCount == 0)
combinedWriteConflictRanges.back().second = point.key;
}
}
}
assert(writeVersion >= newestVersion); assert(writeVersion >= newestVersion);
newestVersion = writeVersion; newestVersion = writeVersion;
Arena arena; const int stringCount = combinedWriteConflictRanges.size() * 2;
const int stringCount = count * 2;
const int stripeSize = 16; const int stripeSize = 16;
SkipList::Finger fingers[stripeSize]; SkipList::Finger fingers[stripeSize];
@@ -616,15 +777,13 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
int ss = stringCount - (stripes - 1) * stripeSize; int ss = stringCount - (stripes - 1) * stripeSize;
for (int s = stripes - 1; s >= 0; s--) { for (int s = stripes - 1; s >= 0; s--) {
for (int i = 0; i * 2 < ss; ++i) { for (int i = 0; i * 2 < ss; ++i) {
const auto &w = writes[s * stripeSize / 2 + i]; const auto &w = combinedWriteConflictRanges[s * stripeSize / 2 + i];
#if DEBUG_VERBOSE #if DEBUG_VERBOSE
printf("Write begin: %s\n", printable(w.begin).c_str()); printf("Write begin: %s\n", printable(w.begin).c_str());
fflush(stdout); fflush(stdout);
#endif #endif
values[i * 2] = {w.begin.p, size_t(w.begin.len)}; values[i * 2] = w.first;
values[i * 2 + 1] = w.end.len > 0 values[i * 2 + 1] = w.second;
? StringRef{w.end.p, size_t(w.end.len)}
: keyAfter(arena, values[i * 2]);
keyUpdates += 3; keyUpdates += 3;
} }
skipList.find(values, fingers, temp, ss); skipList.find(values, fingers, temp, ss);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More