Compare commits

...

14 Commits

Author SHA1 Message Date
6abd8139f0 Fix clangd warnings 2025-05-20 22:25:49 -04:00
57cceaf3b7 Fix an issue with versioned-only benchmark
Previously it was reading some of the keys from unversioned storage.

Also add some more benchmarks
2024-06-19 15:08:16 -07:00
39273424c1 Only search backward for materializing clear range 2024-06-19 12:16:09 -07:00
c4c269ab94 Skip unversioned for adjacent mutations, reverse reads 2024-06-17 12:22:43 -07:00
fcb881f408 Skip unversioned until non-adjacent mutation in facade
Only implemented for forward reads so far
2024-06-17 11:57:36 -07:00
b2ce851d56 Update corpus 2024-06-15 22:16:52 -07:00
e11ee26332 Allow stack to grow in gc
The previous bound was valid in each logical version of the map, but not
for the physical map's structure.
2024-06-15 20:28:43 -07:00
0af75f5e9c Make gRandom inline
I have no idea why I made it static
2024-06-15 20:18:08 -07:00
43ba21329b Mark remainder of rightmost page no_access after gc 2024-06-15 18:11:18 -07:00
3e9c69e857 Update corpus 2024-06-15 09:47:20 -07:00
edb76feadf Remove "next" argument from materializeMutations 2024-06-14 23:40:09 -07:00
2eea70f063 Fix a bug where a range end's version wasn't updated 2024-06-14 23:26:00 -07:00
be3032e2f3 Fix a use of an invalid iterator 2024-06-14 23:25:43 -07:00
b34d559c02 Strengthen valgrind checks 2024-06-14 22:31:05 -07:00
359 changed files with 242 additions and 85 deletions

130
Bench.cpp
View File

@@ -3,6 +3,34 @@
#include <nanobench.h>
void iterBench(const Facade &facade, int64_t version,
const std::string &context) {
ankerl::nanobench::Bench bench;
bench.minEpochIterations(10000);
const auto begin = facade.versioned.begin(version);
const auto end = facade.versioned.end(version);
auto iter = begin;
bench.run("*iter (" + context + ")", [&] { bench.doNotOptimizeAway(*iter); });
iter = begin;
bench.run("++iter (" + context + ")", [&] {
++iter;
if (iter == end) {
iter = begin;
}
});
iter = end;
bench.run("--iter (" + context + ")", [&] {
--iter;
if (iter == begin) {
iter = end;
}
});
}
void monotonicallyIncreasing() {
constexpr int kWindow = 1000;
ankerl::nanobench::Bench bench;
@@ -25,27 +53,7 @@ void monotonicallyIncreasing() {
});
const auto v = facade.getVersion() - kWindow / 2;
const auto begin = facade.versioned.begin(v);
const auto end = facade.versioned.end(v);
auto iter = begin;
bench.run("*iter", [&] { bench.doNotOptimizeAway(*iter); });
iter = begin;
bench.run("++iter", [&] {
++iter;
if (iter == end) {
iter = begin;
}
});
iter = end;
bench.run("--iter", [&] {
--iter;
if (iter == begin) {
iter = end;
}
});
iterBench(facade, v, "monotonically increasing");
bench.run("begin", [&] { facade.versioned.begin(v); });
@@ -56,6 +64,27 @@ void monotonicallyIncreasing() {
});
bench.run("end", [&] { facade.versioned.end(v); });
{
ankerl::nanobench::Bench bench;
bench.batch(kWindow);
bench.run("Facade monotonically-increasing read forward", [&]() {
if (facade.viewAt(facade.getVersion())
.rangeRead(String(), String({0xff}), kWindow, false)
.size() != kWindow) {
abort();
}
});
bench.run("Facade monotonically-increasing read reverse", [&]() {
if (facade.viewAt(facade.getVersion())
.rangeRead(String(), String({0xff}), kWindow, true)
.size() != kWindow) {
abort();
}
});
}
}
void bulkFirstGeq() {
@@ -103,7 +132,66 @@ void bulkFirstGeq() {
[&] { versionedMap.firstGeq(keys, iterators, kNumQueries); });
}
void facadeVersionedOnlyRead() {
Facade facade{0};
constexpr int kNumKeys = 1000;
ankerl::nanobench::Bench bench;
bench.batch(kNumKeys);
const int64_t beginBytes = __builtin_bswap64(0);
const int64_t endBytes = __builtin_bswap64(kNumKeys);
const String begin{(const uint8_t *)&beginBytes, 8};
const String end{(const uint8_t *)&endBytes, 8};
// Insert clear in entire range, so that all reads are served from versioned,
// logically and hopefully physically.
{
weaselab::VersionedMap::Mutation mutations[] = {
{begin.data(), int(begin.size()), end.data(), int(end.size()),
weaselab::VersionedMap::Clear},
};
facade.addMutations(mutations, sizeof(mutations) / sizeof(mutations[0]),
facade.getVersion() + 1);
}
Arena arena;
weaselab::VersionedMap::Mutation *mutations =
new (arena) weaselab::VersionedMap::Mutation[kNumKeys];
for (int i = 0; i < kNumKeys; ++i) {
const int64_t k = __builtin_bswap64(i);
uint8_t *buf = new (arena) uint8_t[8];
memcpy(buf, &k, 8);
mutations[i] = {buf, 8, buf, 8, weaselab::VersionedMap::Set};
}
// Add keys
facade.addMutations(mutations, kNumKeys, facade.getVersion() + 1);
// Populate the unversioned map
facade.addMutations(mutations, kNumKeys, facade.getVersion() + 1);
facade.setOldestVersion(facade.getVersion() - 1, /*force*/ true);
iterBench(facade, facade.getVersion(), "adjacent sets/clears");
bench.run("Facade versioned-only read forward", [&]() {
if (facade.viewAt(facade.getVersion())
.rangeRead(begin, end, kNumKeys, false)
.size() != kNumKeys) {
abort();
}
});
bench.run("Facade versioned-only read reverse", [&]() {
if (facade.viewAt(facade.getVersion())
.rangeRead(begin, end, kNumKeys, true)
.size() != kNumKeys) {
abort();
}
});
}
int main() {
monotonicallyIncreasing();
bulkFirstGeq();
facadeVersionedOnlyRead();
}

View File

@@ -53,12 +53,13 @@ struct Facade {
do {
--iter;
auto m = *iter;
const auto mBegin =
weaselab::VersionedMap::Key{m.param1, m.param1Len};
const auto mEnd =
auto mBegin = weaselab::VersionedMap::Key{m.param1, m.param1Len};
auto mEnd =
m.type == weaselab::VersionedMap::Set || m.param2Len == 0
? weaselab::VersionedMap::Key{m.param1, m.param1Len + 1}
: weaselab::VersionedMap::Key{m.param2, m.param2Len};
// Read from unversioned down to mEnd
if (unversionedIter != beginIter) {
--unversionedIter;
for (; unversionedIter->first >= mEnd && limit > 0;
@@ -73,6 +74,12 @@ struct Facade {
if (limit == 0) {
return result;
}
bool pointMutation =
m.type == weaselab::VersionedMap::Set || m.param2Len == 0;
// Read from versioned until non-adjacent
readVersionedReverse:
switch (m.type) {
case weaselab::VersionedMap::Set: {
result.emplace_back(String(mBegin.p, mBegin.len),
@@ -85,7 +92,31 @@ struct Facade {
case weaselab::VersionedMap::Clear:
break;
}
if (m.type == weaselab::VersionedMap::Set || m.param2Len == 0) {
if (iter != endIter) {
--iter;
auto tmpM = *iter;
const auto tmpMBegin =
weaselab::VersionedMap::Key{tmpM.param1, tmpM.param1Len};
const auto tmpMEnd =
tmpM.type == weaselab::VersionedMap::Set || tmpM.param2Len == 0
? weaselab::VersionedMap::Key{tmpM.param1,
tmpM.param1Len + 1}
: weaselab::VersionedMap::Key{tmpM.param2, tmpM.param2Len};
if (tmpMEnd >= mBegin) {
// Adjacent with last (temporally) mutation
mBegin = tmpMBegin;
mEnd = tmpMEnd;
m = tmpM;
pointMutation = false;
goto readVersionedReverse;
} else {
++iter;
}
}
// Advance unversioned iter
if (pointMutation) {
if (unversionedIter != facade->unversioned.end() &&
unversionedIter->first < mBegin) {
++unversionedIter;
@@ -112,16 +143,17 @@ struct Facade {
return result;
} else {
auto unversionedIter = facade->unversioned.lower_bound(begin);
for (auto iter = versionedIter[0]; iter != versionedIter[1]; ++iter) {
for (auto iter = versionedIter[0]; iter != versionedIter[1];) {
auto m = *iter;
const auto mBegin =
weaselab::VersionedMap::Key{m.param1, m.param1Len};
const auto mEnd =
auto mBegin = weaselab::VersionedMap::Key{m.param1, m.param1Len};
auto mEnd =
m.type == weaselab::VersionedMap::Set || m.param2Len == 0
? weaselab::VersionedMap::Key{m.param1, m.param1Len + 1}
: weaselab::VersionedMap::Key{m.param2, m.param2Len};
// Read from unversioned up to mBegin
for (; unversionedIter != facade->unversioned.end() &&
(unversionedIter->first <=> mBegin) < 0 && limit > 0;) {
unversionedIter->first < mBegin && limit > 0;) {
result.push_back(*unversionedIter);
--limit;
++unversionedIter;
@@ -129,6 +161,12 @@ struct Facade {
if (limit == 0) {
return result;
}
bool pointMutation =
m.type == weaselab::VersionedMap::Set || m.param2Len == 0;
// Read from versioned until non-adjacent
readVersionedForward:
switch (m.type) {
case weaselab::VersionedMap::Set: {
result.emplace_back(String(mBegin.p, mBegin.len),
@@ -141,19 +179,42 @@ struct Facade {
case weaselab::VersionedMap::Clear:
break;
}
if (m.type == weaselab::VersionedMap::Set || m.param2Len == 0) {
++iter;
if (iter != versionedIter[1]) {
auto tmpM = *iter;
if (weaselab::VersionedMap::Key{tmpM.param1, tmpM.param1Len} <=
mEnd) {
// Adjacent with last mutation
mBegin = weaselab::VersionedMap::Key{tmpM.param1, tmpM.param1Len};
mEnd = tmpM.type == weaselab::VersionedMap::Set ||
tmpM.param2Len == 0
? weaselab::VersionedMap::Key{tmpM.param1,
tmpM.param1Len + 1}
: weaselab::VersionedMap::Key{tmpM.param2,
tmpM.param2Len};
m = tmpM;
pointMutation = false;
goto readVersionedForward;
}
}
// Advance unversioned iter
if (pointMutation) {
// Point mutation
if (unversionedIter != facade->unversioned.end() &&
(unversionedIter->first <=> mBegin) == 0) {
unversionedIter->first <= mBegin) {
++unversionedIter;
}
assert(unversionedIter ==
facade->unversioned.lower_bound(String(mEnd.p, mEnd.len)));
} else {
// Range mutation
unversionedIter =
facade->unversioned.lower_bound(String(mEnd.p, mEnd.len));
}
}
// Finish reading from unversioned
for (; unversionedIter != facade->unversioned.end() &&
unversionedIter->first < end && limit > 0;
++unversionedIter) {
@@ -178,15 +239,17 @@ struct Facade {
versioned.addMutations(mutations, numMutations, version);
}
void setOldestVersion(int64_t version) {
void setOldestVersion(int64_t version, bool force = false) {
// Don't scan and apply mutations every time setOldestVersion is called.
oldestVersion = version;
if (!force) {
if (version >= nextPurgeVersion) {
nextPurgeVersion = versioned.getVersion();
} else {
return;
}
}
for (auto iter = versioned.begin(version), end = versioned.end(version);
iter != end; ++iter) {

View File

@@ -393,7 +393,7 @@ inline Random seededRandom() {
return Random{seed[0], seed[1]};
}
static thread_local Random gRandom = seededRandom();
inline thread_local Random gRandom = seededRandom();
// ==================== END RANDOM IMPL ====================

View File

@@ -263,7 +263,7 @@ struct MemManager {
if (next == firstUnaddressable) {
mprotectSafe(base + firstUnaddressable, kUpsizeBytes,
PROT_READ | PROT_WRITE);
VALGRIND_MAKE_MEM_UNDEFINED(base + firstUnaddressable, kUpsizeBytes);
VALGRIND_MAKE_MEM_NOACCESS(base + firstUnaddressable, kUpsizeBytes);
firstUnaddressable += kUpsizeNodes;
#if SHOW_MEMORY
mmapBytes = getBytes();
@@ -278,15 +278,18 @@ struct MemManager {
}
}
VALGRIND_MAKE_MEM_UNDEFINED(base + next, sizeof(Node));
return next++;
}
void gc(const uint32_t *roots, int numRoots, int64_t oldestVersion) {
// Calculate reachable set
BitSet reachable{next};
// Each node has at most 3 children and nodes along the search path aren't
// in the stack, so we need 2 * kPathLengthUpperBound
uint32_t stack[2 * kPathLengthUpperBound];
Arena arena;
constexpr int kInitialStackCapacity = 128;
int64_t stackCapacity = kInitialStackCapacity;
uint32_t stackStack[kInitialStackCapacity];
uint32_t *stack = stackStack;
int stackIndex = 0;
auto tryPush = [&]([[maybe_unused]] uint32_t parent, uint32_t child) {
if (!reachable.set(child)) {
@@ -295,7 +298,12 @@ struct MemManager {
printf(" GC: reach: %u (parent %u)\n", child, parent);
}
#endif
assert(stackIndex < int(sizeof(stack) / sizeof(stack[0])));
if (stackIndex == stackCapacity) [[unlikely]] {
auto *old = stack;
stackCapacity *= 2;
stack = new (arena) uint32_t[stackCapacity];
memcpy(stack, old, stackIndex * sizeof(stack[0]));
}
stack[stackIndex++] = child;
}
};
@@ -377,6 +385,9 @@ struct MemManager {
#endif
}
next = max + 1;
assert(firstUnaddressable >= next);
VALGRIND_MAKE_MEM_NOACCESS(base + next,
(firstUnaddressable - next) * sizeof(Node));
}
int64_t getBytes() const {
@@ -954,7 +965,10 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
if (engulfLeft && engulfRight) {
insert({next->getKey(), next->keyLen}, {}, /*endRange*/ true, copy);
if (found) {
remove(iter);
move<std::memory_order_relaxed, false>(copy, latestVersion);
// Point to the same entry as iter pointed to, but it's not
// invalidated
remove(copy);
}
} else if (engulfLeft) {
assert(found);
@@ -963,6 +977,10 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
/*endRange*/ true, iter);
} else if (engulfRight) {
insert({m.param1, m.param1Len}, {}, /*endRange*/ false, iter);
move<std::memory_order_relaxed, true>(iter, latestVersion);
assert(iter.searchPathSize() > 0 &&
mm.base[iter.backNode()].entry == next);
insert({next->getKey(), next->keyLen}, {}, /*endRange*/ true, iter);
} else {
insert({m.param1, m.param1Len}, {{nullptr, -1}}, /*endRange*/ false,
iter);
@@ -1200,8 +1218,11 @@ VersionedMap::Iterator::operator*() const {
return impl->mutations[impl->mutationIndex];
}
void materializeMutations(VersionedMap::Iterator::Impl *impl, const Entry *prev,
const Entry *next) {
void materializeMutations(VersionedMap::Iterator::Impl *impl,
const Entry *prev) {
const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry;
impl->mutationCount = 0;
if (entry.clearTo()) {
if (prev == nullptr) {
Finger copy;
impl->finger.copyTo(copy);
@@ -1212,18 +1233,7 @@ void materializeMutations(VersionedMap::Iterator::Impl *impl, const Entry *prev,
assert(!impl->map->mm.base[impl->finger.backNode()].entry->clearTo());
}
}
if (next == nullptr) {
Finger copy;
impl->finger.copyTo(copy);
impl->map->move<std::memory_order_acquire, true>(copy, impl->version);
if (copy.searchPathSize() > 0) {
next = impl->map->mm.base[copy.backNode()].entry;
}
}
const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry;
impl->mutationCount = 0;
if (entry.clearTo()) {
impl->mutations[impl->mutationCount++] = {
prev->getKey(),
entry.getKey(),
@@ -1234,7 +1244,6 @@ void materializeMutations(VersionedMap::Iterator::Impl *impl, const Entry *prev,
}
if (entry.pointMutation()) {
if (entry.valLen < 0 /* pointClear */) {
assert(next == nullptr || !next->clearTo());
impl->mutations[impl->mutationCount++] = {
entry.getKey(), nullptr, entry.keyLen, 0,
VersionedMap::Clear, entry.pointVersion};
@@ -1260,7 +1269,7 @@ VersionedMap::Iterator &VersionedMap::Iterator::operator++() {
if (impl->finger.searchPathSize() == 0) {
break;
}
materializeMutations(impl, &entry, nullptr);
materializeMutations(impl, &entry);
} while (impl->mutationCount == 0);
impl->mutationIndex = 0;
@@ -1294,13 +1303,11 @@ VersionedMap::Iterator &VersionedMap::Iterator::operator--() {
impl->finger.push(c, true);
}
const Entry *next = nullptr;
for (;;) {
materializeMutations(impl, nullptr, next);
materializeMutations(impl, nullptr);
if (impl->mutationCount > 0) {
break;
}
next = impl->map->mm.base[impl->finger.backNode()].entry;
impl->map->move<std::memory_order_acquire, false>(impl->finger,
impl->version);
}
@@ -1309,13 +1316,12 @@ VersionedMap::Iterator &VersionedMap::Iterator::operator--() {
}
do {
const Entry *entry = impl->map->mm.base[impl->finger.backNode()].entry;
impl->map->move<std::memory_order_acquire, false>(impl->finger,
impl->version);
if (impl->finger.searchPathSize() == 0) {
break;
}
materializeMutations(impl, nullptr, entry);
materializeMutations(impl, nullptr);
} while (impl->mutationCount == 0);
impl->mutationIndex = impl->mutationCount - 1;
return *this;
@@ -1390,7 +1396,7 @@ void VersionedMap::Impl::StepwiseFirstGeq::end() {
if (finger.searchPathSize() == 0) {
break;
} else {
materializeMutations(iterator->impl, prev, nullptr);
materializeMutations(iterator->impl, prev);
for (int j = 0; j < iterator->impl->mutationCount; ++j) {
if (geq(iterator->impl->mutations[j], *key)) {
iterator->impl->mutationIndex = j;
@@ -1542,7 +1548,7 @@ VersionedMap::Iterator VersionedMap::begin(int64_t version) const {
const Entry *prev = nullptr;
for (;;) {
if (result.impl->finger.searchPathSize() > 0) {
materializeMutations(result.impl, prev, nullptr);
materializeMutations(result.impl, prev);
if (result.impl->mutationCount > 0) {
break;
}

View File

@@ -1,2 +0,0 @@
~0<><30>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> zzzz zzz zz<7A><7A><EFBFBD><EFBFBD><EFBFBD>zz zzNz zzzz zzz zzz S<><53><EFBFBD><EFBFBD><EFBFBD>s<EFBFBD> 5[<5B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><ECA0A0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

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.

View File

@@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD>

View File

@@ -0,0 +1 @@
Z <0B>G

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1 +0,0 @@
'*9

Binary file not shown.

View File

@@ -1 +0,0 @@
k<04><><EFBFBD> <0B><><EFBFBD><EFBFBD><EFBFBD> <0B>'<27>'*<2A>

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