Storage Engine API
partitioned.h
Go to the documentation of this file.
1 
29 #pragma once
30 
31 #include <algorithm>
32 #include <cstdlib>
33 #include <iterator>
34 #include <memory>
35 #include <numeric>
36 #include <utility>
37 #include <vector>
38 
39 #include <boost/align/aligned_allocator.hpp>
40 
41 #include "mongo/stdx/mutex.h"
42 #include "mongo/util/assert_util.h"
43 #include "mongo/util/with_alignment.h"
44 
45 namespace mongo {
46 
47 inline std::size_t partitionOf(const char x, const std::size_t nPartitions) {
48  return static_cast<unsigned char>(x) % nPartitions;
49 }
50 inline std::size_t partitionOf(const unsigned char x, const std::size_t nPartitions) {
51  return x % nPartitions;
52 }
53 inline std::size_t partitionOf(const signed char x, const std::size_t nPartitions) {
54  return static_cast<unsigned char>(x) % nPartitions;
55 }
56 inline std::size_t partitionOf(const int x, const std::size_t nPartitions) {
57  return static_cast<unsigned int>(x) % nPartitions;
58 }
59 inline std::size_t partitionOf(const unsigned int x, const std::size_t nPartitions) {
60  return x % nPartitions;
61 }
62 inline std::size_t partitionOf(const short x, const std::size_t nPartitions) {
63  return static_cast<unsigned short>(x) % nPartitions;
64 }
65 inline std::size_t partitionOf(const unsigned short x, const std::size_t nPartitions) {
66  return x % nPartitions;
67 }
68 inline std::size_t partitionOf(const long x, const std::size_t nPartitions) {
69  return static_cast<unsigned long>(x) % nPartitions;
70 }
71 inline std::size_t partitionOf(const unsigned long x, const std::size_t nPartitions) {
72  return x % nPartitions;
73 }
74 inline std::size_t partitionOf(const long long x, const std::size_t nPartitions) {
75  return static_cast<unsigned long long>(x) % nPartitions;
76 }
77 inline std::size_t partitionOf(const unsigned long long x, const std::size_t nPartitions) {
78  return x % nPartitions;
79 }
80 inline std::size_t partitionOf(const wchar_t x, const std::size_t nPartitions) {
81  return x % nPartitions;
82 }
83 inline std::size_t partitionOf(const char16_t x, const std::size_t nPartitions) {
84  return x % nPartitions;
85 }
86 inline std::size_t partitionOf(const char32_t x, const std::size_t nPartitions) {
87  return x % nPartitions;
88 }
89 
95 template <typename T>
96 struct Partitioner {
97  std::size_t operator()(const T& x, const std::size_t nPartitions) {
98  return partitionOf(x, nPartitions);
99  }
100 };
101 
102 namespace partitioned_detail {
103 
104 using CacheAlignedMutex = CacheAligned<stdx::mutex>;
105 
106 template <typename Key, typename Value>
107 Key getKey(const std::pair<Key, Value>& pair) {
108  return std::get<0>(pair);
109 }
110 
111 template <typename Key>
112 Key getKey(const Key& key) {
113  return key;
114 }
115 
116 template <typename T>
117 inline std::vector<stdx::unique_lock<stdx::mutex>> lockAllPartitions(T& mutexes) {
118  std::vector<stdx::unique_lock<stdx::mutex>> result;
119  result.reserve(mutexes.size());
120  std::transform(mutexes.begin(), mutexes.end(), std::back_inserter(result), [](auto&& mutex) {
121  return stdx::unique_lock<stdx::mutex>{mutex};
122  });
123  return result;
124 }
125 } // namespace partitioned_detail
126 
134 template <typename AssociativeContainer,
135  std::size_t nPartitions = 16,
137 class Partitioned {
138 private:
139  // Used to create an iterator representing the end of the partitioned structure.
140  struct IteratorEndTag {};
141 
142 public:
143  static_assert(nPartitions > 0, "cannot create partitioned structure with 0 partitions");
144  using value_type = typename AssociativeContainer::value_type;
145  using key_type = typename AssociativeContainer::key_type;
146  using PartitionId = std::size_t;
147 
153  class All {
154  private:
159  explicit All(Partitioned& partitionedContainer)
160  : _lockGuards(partitioned_detail::lockAllPartitions(partitionedContainer._mutexes)),
161  _partitionedContainer(&partitionedContainer) {}
162 
163  public:
167  auto begin() & {
168  return this->_partitionedContainer->_partitions.begin();
169  }
170 
174  auto end() & {
175  return this->_partitionedContainer->_partitions.end();
176  }
177 
181  auto begin() const& {
182  return this->_partitionedContainer->_partitions.begin();
183  }
184  void begin() && = delete;
185 
189  auto end() const& {
190  return this->_partitionedContainer->_partitions.end();
191  }
192  void end() && = delete;
193 
197  std::size_t size() const {
198  return std::accumulate(
199  this->_partitionedContainer->_partitions.begin(),
200  this->_partitionedContainer->_partitions.end(),
201  std::size_t{0},
202  [](auto&& total, auto&& partition) { return total + partition.size(); });
203  }
204 
208  bool empty() const {
209  return std::all_of(this->_partitionedContainer->_partitions.begin(),
210  this->_partitionedContainer->_partitions.end(),
211  [](auto&& partition) { return partition.empty(); });
212  }
213 
217  std::size_t count(const key_type& key) const {
218  auto partitionId = KeyPartitioner()(key, nPartitions);
219  return this->_partitionedContainer->_partitions[partitionId].count(key);
220  }
221 
225  void clear() {
226  for (auto&& partition : this->_partitionedContainer->_partitions) {
227  partition.clear();
228  }
229  }
230 
234  void insert(value_type value) & {
235  const auto partitionId =
236  KeyPartitioner()(partitioned_detail::getKey(value), nPartitions);
237  this->_partitionedContainer->_partitions[partitionId].insert(std::move(value));
238  }
239  void insert(value_type)&& = delete;
240 
244  std::size_t erase(const key_type& key) & {
245  const auto partitionId = KeyPartitioner()(key, nPartitions);
246  return this->_partitionedContainer->_partitions[partitionId].erase(key);
247  }
248  void erase(const key_type&) && = delete;
249 
250  private:
251  friend class Partitioned;
252 
253  std::vector<stdx::unique_lock<stdx::mutex>> _lockGuards;
255  };
256 
262  class OnePartition {
263  public:
267  AssociativeContainer* operator->() const& {
268  return &this->_partitioned->_partitions[_id];
269  }
270  void operator->() && = delete;
271 
275  AssociativeContainer& operator*() const& {
276  return this->_partitioned->_partitions[_id];
277  }
278  void operator*() && = delete;
279 
280  private:
281  friend class Partitioned;
282 
288  OnePartition(Partitioned& partitioned, PartitionId partitionId)
289  : _partitionLock(partitioned._mutexes[partitionId]),
290  _partitioned(&partitioned),
291  _id(partitionId) {}
292 
293  stdx::unique_lock<stdx::mutex> _partitionLock;
296  };
297 
301  Partitioned() : _mutexes(nPartitions), _partitions(nPartitions) {}
302 
303  Partitioned(const Partitioned&) = delete;
304  Partitioned(Partitioned&&) = default;
305  Partitioned& operator=(const Partitioned&) = delete;
306  Partitioned& operator=(Partitioned&&) = default;
307  ~Partitioned() = default;
308 
313  bool empty() const {
314  const auto all = partitioned_detail::lockAllPartitions(this->_mutexes);
315  return std::all_of(this->_partitions.begin(),
316  this->_partitions.end(),
317  [](auto&& partition) { return partition.empty(); });
318  }
319 
324  std::size_t size() const {
325  const auto all = partitioned_detail::lockAllPartitions(this->_mutexes);
326  return std::accumulate(
327  this->_partitions.begin(),
328  this->_partitions.end(),
329  std::size_t{0},
330  [](auto&& total, auto&& partition) { return total + partition.size(); });
331  }
332 
337  std::size_t count(const key_type& key) & {
338  auto partition = this->lockOnePartition(key);
339  return partition->count(key);
340  }
341  void count(const key_type&) && = delete;
342 
346  void clear() {
347  auto all = this->lockAllPartitions();
348  all.clear();
349  }
350 
355  void insert(const value_type value) & {
356  auto partition = this->lockOnePartitionById(
357  KeyPartitioner()(partitioned_detail::getKey(value), nPartitions));
358  partition->insert(std::move(value));
359  }
360  void insert(const value_type) && = delete;
361 
366  std::size_t erase(const key_type& key) & {
367  auto partition = this->lockOnePartition(key);
368  return partition->erase(key);
369  }
370  void erase(const key_type&) && = delete;
371 
373  return All{*this};
374  }
375 
377  return OnePartition{*this, KeyPartitioner()(key, nPartitions)};
378  }
379 
381  return OnePartition{*this, id};
382  }
383 
384 private:
385  using CacheAlignedAssociativeContainer = CacheAligned<AssociativeContainer>;
386 
387  template <typename T>
388  using AlignedVector = std::vector<T, boost::alignment::aligned_allocator<T>>;
389 
390  // These two vectors parallel each other, but we keep them separate so that we can return an
391  // iterator over `_partitions` from within All.
394 };
395 } // namespace mongo
auto begin() &
Returns an iterator at the start of the partitions.
Definition: partitioned.h:167
stdx::unique_lock< stdx::mutex > _partitionLock
Definition: partitioned.h:293
std::size_t size() const
Returns the number of elements in all partitions, summed together.
Definition: partitioned.h:197
Copyright (C) 2014 MongoDB Inc.
Definition: bson_collection_catalog_entry.cpp:38
typename AssociativeContainer::value_type value_type
Definition: partitioned.h:144
The default partitioning policy: If using a numeric built-in type, will use the lower bits of a numbe...
Definition: partitioned.h:96
BSONObj key
Definition: btree_interface.cpp:334
Key getKey(const Key &key)
Definition: partitioned.h:112
OnePartition lockOnePartitionById(PartitionId id) &
Definition: partitioned.h:380
std::size_t partitionOf(const char x, const std::size_t nPartitions)
Definition: partitioned.h:47
void clear()
Empties each container within each partition.
Definition: partitioned.h:225
std::vector< stdx::unique_lock< stdx::mutex > > _lockGuards
Definition: partitioned.h:253
OnePartition(Partitioned &partitioned, PartitionId partitionId)
Acquires locks for the ith partition.
Definition: partitioned.h:288
typename AssociativeContainer::key_type key_type
Definition: partitioned.h:145
Used to protect access to all partitions of this partitioned associative structure.
Definition: partitioned.h:153
auto begin() const &
Returns an iterator at the start of the partitions.
Definition: partitioned.h:181
void clear()
Empties all partitions.
Definition: partitioned.h:346
AssociativeContainer * operator->() const &
Returns a pointer to the structure in this partition.
Definition: partitioned.h:267
CacheAligned< stdx::mutex > CacheAlignedMutex
Definition: partitioned.h:104
std::vector< T, boost::alignment::aligned_allocator< T > > AlignedVector
Definition: partitioned.h:388
Partitioned * _partitionedContainer
Definition: partitioned.h:254
RecordId _id
Definition: wiredtiger_index.cpp:1132
AlignedLockStats _partitions[NumPartitions]
Definition: lock_state.cpp:103
Partitioned * _partitioned
Definition: partitioned.h:294
All lockAllPartitions() &
Definition: partitioned.h:372
AlignedVector< CacheAlignedAssociativeContainer > _partitions
Definition: partitioned.h:393
A templated class used to partition an associative container like a set or a map to increase scalabil...
Definition: partitioned.h:137
std::size_t erase(const key_type &key) &
Erases one entry from the partitioned structure, returns the number of entries removed.
Definition: partitioned.h:244
std::vector< stdx::unique_lock< stdx::mutex > > lockAllPartitions(T &mutexes)
Definition: partitioned.h:117
PartitionId _id
Definition: partitioned.h:295
auto end() const &
Returns an iterator at the end of the partitions.
Definition: partitioned.h:189
CacheAligned< AssociativeContainer > CacheAlignedAssociativeContainer
Definition: partitioned.h:385
AlignedVector< partitioned_detail::CacheAlignedMutex > _mutexes
Definition: partitioned.h:392
std::size_t count(const key_type &key) &
Returns the number of entries with the given key.
Definition: partitioned.h:337
All(Partitioned &partitionedContainer)
Acquires locks for all partitions.
Definition: partitioned.h:159
void insert(const value_type value) &
Inserts a single value into the partitioned structure.
Definition: partitioned.h:355
Definition: partitioned.h:140
auto end() &
Returns an iterator at the end of the partitions.
Definition: partitioned.h:174
std::size_t operator()(const T &x, const std::size_t nPartitions)
Definition: partitioned.h:97
Used to protect access to a single partition of a Partitioned.
Definition: partitioned.h:262
std::size_t size() const
Returns the number of elements in all partitions, summed together.
Definition: partitioned.h:324
std::size_t count(const key_type &key) const
Returns the number of entries with the given key.
Definition: partitioned.h:217
void insert(value_type value) &
Inserts value into its designated partition.
Definition: partitioned.h:234
OnePartition lockOnePartition(const key_type key) &
Definition: partitioned.h:376
Partitioned()
Constructs a partitioned version of a AssociativeContainer, with nPartitions partitions.
Definition: partitioned.h:301
bool empty() const
Returns true if each partition is empty.
Definition: partitioned.h:208
Key getKey(const std::pair< Key, Value > &pair)
Definition: partitioned.h:107
std::size_t erase(const key_type &key) &
Erases one entry from the partitioned structure.
Definition: partitioned.h:366
std::size_t PartitionId
Definition: partitioned.h:146
bool empty() const
Returns true if each partition is empty.
Definition: partitioned.h:313
AssociativeContainer & operator*() const &
Returns a reference to the structure in this partition.
Definition: partitioned.h:275