Merge pull request #6575 from jzhou77/version-vector
Use boost::flat_map and optimize getDelta/applyDelta
This commit is contained in:
commit
402b463a26
|
@ -23,15 +23,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "fdbclient/FDBTypes.h"
|
||||
#include "fdbclient/Knobs.h"
|
||||
|
||||
struct VersionVector {
|
||||
std::unordered_map<Tag, Version> versions;
|
||||
boost::container::flat_map<Tag, Version> versions;
|
||||
Version maxVersion; // Specifies the max version in this version vector. (Note:
|
||||
// there may or may not be a corresponding entry for this
|
||||
// version in the "versions" map.)
|
||||
|
@ -39,6 +38,12 @@ struct VersionVector {
|
|||
VersionVector() : maxVersion(invalidVersion) {}
|
||||
VersionVector(Version version) : maxVersion(version) {}
|
||||
|
||||
private:
|
||||
// Only invoked by getDelta() and applyDelta(), where tag has been validated
|
||||
// and version is guaranteed to be larger than the existing value.
|
||||
inline void setVersionNoCheck(const Tag& tag, Version version) { versions[tag] = version; }
|
||||
|
||||
public:
|
||||
Version getMaxVersion() const { return maxVersion; }
|
||||
|
||||
int size() const { return versions.size(); }
|
||||
|
@ -92,17 +97,11 @@ struct VersionVector {
|
|||
if (CLIENT_KNOBS->SEND_ENTIRE_VERSION_VECTOR) {
|
||||
delta = *this;
|
||||
} else {
|
||||
std::map<Version, std::set<Tag>> tmpVersionMap; // order versions
|
||||
for (const auto& [tag, version] : versions) {
|
||||
if (version > refVersion) {
|
||||
tmpVersionMap[version].insert(tag);
|
||||
delta.setVersionNoCheck(tag, version);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& [version, tags] : tmpVersionMap) {
|
||||
delta.setVersion(tags, version);
|
||||
}
|
||||
|
||||
delta.maxVersion = maxVersion;
|
||||
}
|
||||
}
|
||||
|
@ -122,17 +121,11 @@ struct VersionVector {
|
|||
if (CLIENT_KNOBS->SEND_ENTIRE_VERSION_VECTOR) {
|
||||
*this = delta;
|
||||
} else {
|
||||
std::map<Version, std::set<Tag>> tmpVersionMap; // order versions
|
||||
for (const auto& [tag, version] : delta.versions) {
|
||||
if (version > maxVersion) {
|
||||
tmpVersionMap[version].insert(tag);
|
||||
setVersionNoCheck(tag, version);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& [version, tags] : tmpVersionMap) {
|
||||
setVersion(tags, version);
|
||||
}
|
||||
|
||||
maxVersion = delta.maxVersion;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <iterator>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
|
@ -227,6 +228,30 @@ struct vector_like_traits<std::unordered_map<Key, T, Hash, Pred, Allocator>> : s
|
|||
}
|
||||
};
|
||||
|
||||
template <class Key, class T, class Compare, class Allocator>
|
||||
struct vector_like_traits<boost::container::flat_map<Key, T, Compare, Allocator>> : std::true_type {
|
||||
using Vec = boost::container::flat_map<Key, T, Compare, Allocator>;
|
||||
using value_type = std::pair<Key, T>;
|
||||
using iterator = typename Vec::const_iterator;
|
||||
using insert_iterator = std::insert_iterator<Vec>;
|
||||
|
||||
template <class Context>
|
||||
static size_t num_entries(const Vec& v, Context&) {
|
||||
return v.size();
|
||||
}
|
||||
template <class Context>
|
||||
static void reserve(Vec& v, size_t size, Context&) {}
|
||||
|
||||
template <class Context>
|
||||
static insert_iterator insert(Vec& v, Context&) {
|
||||
return std::inserter(v, v.end());
|
||||
}
|
||||
template <class Context>
|
||||
static iterator begin(const Vec& v, Context&) {
|
||||
return v.begin();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Key, class Compare, class Allocator>
|
||||
struct vector_like_traits<std::set<Key, Compare, Allocator>> : std::true_type {
|
||||
using Vec = std::set<Key, Compare, Allocator>;
|
||||
|
|
|
@ -22,17 +22,19 @@
|
|||
#define FLOW_SERIALIZE_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <deque>
|
||||
#include <set>
|
||||
#include "flow/ProtocolVersion.h"
|
||||
#include "flow/Error.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "flow/Arena.h"
|
||||
#include "flow/Error.h"
|
||||
#include "flow/FileIdentifier.h"
|
||||
#include "flow/ObjectSerializer.h"
|
||||
#include "flow/ProtocolVersion.h"
|
||||
#include "flow/network.h"
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
|
||||
// Though similar, is_binary_serializable cannot be replaced by std::is_pod, as doing so would prefer
|
||||
// memcpy over a defined serialize() method on a POD struct. As not all of our structs are packed,
|
||||
|
@ -268,6 +270,27 @@ inline void load(Archive& ar, std::map<K, V>& value) {
|
|||
ASSERT(ar.protocolVersion().isValid());
|
||||
}
|
||||
|
||||
template <class Archive, class K, class V>
|
||||
inline void save(Archive& ar, const boost::container::flat_map<K, V>& value) {
|
||||
ar << (int)value.size();
|
||||
for (const auto& it : value) {
|
||||
ar << it.first << it.second;
|
||||
}
|
||||
ASSERT(ar.protocolVersion().isValid());
|
||||
}
|
||||
template <class Archive, class K, class V>
|
||||
inline void load(Archive& ar, boost::container::flat_map<K, V>& value) {
|
||||
int s;
|
||||
ar >> s;
|
||||
value.clear();
|
||||
for (int i = 0; i < s; ++i) {
|
||||
std::pair<K, V> p;
|
||||
ar >> p.first >> p.second;
|
||||
value.emplace(p);
|
||||
}
|
||||
ASSERT(ar.protocolVersion().isValid());
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma intrinsic(memcpy)
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue