1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 2017 Couchbase, Inc
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 * This header file contains the abstract base class for the classes that hold
20 * ordered sequence of items in memory. This is not generic, holds only ordered
21 * seq of OrderedStoredValue's. (OrderedStoredValue is the in-memory
22 * representation of an
33 #include "memcached/engine_error.h"
34 #include "stored-value.h"
36 /* [EPHE TODO]: Check if uint64_t can be used instead */
37 using seqno_t = int64_t;
40 * SequenceList is the abstract base class for the classes that hold ordered
41 * sequence of items in memory. To store/retreive items sequencially in memory,
42 * in our multi-threaded, monotonically increasing seq model, we need these
43 * classes around basic data structures like Linkedlist or Skiplist.
45 * 'OrderedStoredValue' is the in-memory representation of an item that can be
46 * stored sequentially and SequenceList derivatives store a sequence of
47 * 'OrderedStoredValues'. Based on the implementation of SequenceList,
48 * OrderedStoredValue might have to carry an intrusive component that
49 * is necessary for the list.
51 * SequenceList expects the module that contains it, takes the responsibility
52 * of serializing the OrderedStoredValue. SequenceList only guarentees to hold
53 * the OrderedStoredValue in the order they are sent to it. For this it forces
54 * the write calls to pass the seq lock held by them
56 * Note: These classes only handle the position of the 'OrderedStoredValue' in
57 * the ordered sequence desired. They do not update a OrderedStoredValue.
59 * In the file 'item', 'OrderedStoredValue' are used interchangeably
61 * [EPHE TODO]: create a documentation (with diagrams) explaining write, update,
62 * rangeRead and Clean Up
67 * Abstract base class for implementation of range iterators in derived
68 * classes of SequenceList.
70 * (a) The API is for unidirectional (forward only) iterator.
71 * (b) Iterator cannot be invalidated while in use.
72 * (c) Reading all the items from the iterator results in point-in-time
74 * (d) Only 1 iterator can be created for now.
75 * (e) Currently iterator can be created only from start till end
77 class RangeIteratorImpl {
79 virtual ~RangeIteratorImpl() {
83 * Returns the stored item at iterator's position
85 virtual OrderedStoredValue& operator*() const = 0;
88 * Pre increment of the iterator position
90 * Note: We do not allow post increment for now as we support only
91 * one iterator at a time. (hence, we don't create a temp copy
92 * of the iterator obj)
94 virtual RangeIteratorImpl& operator++() = 0;
97 * Curr iterator position, indicated by the seqno of the item at that
100 virtual seqno_t curr() const = 0;
103 * End position of iterator, indicated by the seqno > highest_seqno
104 * in the iterator range
106 virtual seqno_t end() const = 0;
111 * Indicates whether the updateListElem is successful or the list is
113 * only appends at the moment.
115 enum class UpdateStatus { Success, Append };
118 * RangeIterator for a SequenceList objects.
120 * The iterator is unidirectional (forward only) and cannot be invalidated
121 * while in use. That means reading the items in the iterator results in a
122 * valid point-in-time snapshot. But this adds a caveat that while an
123 * iterator instance is active, certain invariants are to be met to get the
124 * snapshot, and this happens at the expense of increased memory usage.
126 * Implementation follows the pimpl idiom. This class serves as a wrapper
127 * for the abstract base class that defines the APIs for range iteration on
128 * the derived concrete classes of the SequenceList. It calls the range
129 * iterators of the concrete classes polymorphically at runtime. However
130 * clients get this statically typed "RangeIterator" object when they
131 * request for an iterator for a SequenceList object.
134 * 1. Create an iterator instance using SequenceList::makeRangeIterator()
135 * 2. Iterate (read) through all the list elements.
136 * 3. Delete the iterator.
137 * Note: (a) Do not hold the iterator for long, as it will result in stale
138 * items in list and hence increased memory usage.
139 * (b) Make sure to delete the iterator after using it.
140 * (c) For now, we allow on one RangeIterator. Try to create more
141 * iterators will result in the create call(s) being blocked.
143 class RangeIterator {
145 RangeIterator(std::unique_ptr<RangeIteratorImpl> rangeIterImpl);
148 MSVC does not do "return value optimization" if copy constructor is
149 defined before move constructor
150 (http://stackoverflow.com/questions/29459040)
152 RangeIterator(RangeIterator&& other)
153 : rangeIterImpl(std::move(other.rangeIterImpl)) {
156 RangeIterator(RangeIterator& other) = delete;
159 * Returns the stored item at iterator's position
161 OrderedStoredValue& operator*() const;
164 * Pre increment of the iterator position
166 RangeIterator& operator++();
169 * Curr iterator position, indicated by the seqno of the item at that
175 * Curr iterator position, indicated by the seqno of the item at that
181 /* Pointer to the abstract class of range iterator implementation */
182 std::unique_ptr<RangeIteratorImpl> rangeIterImpl;
185 virtual ~SequenceList() {
189 * Add a new item at the end of the list.
191 * @param seqLock A sequence lock the calling module is expected to hold.
192 * @param v Ref to orderedStoredValue which will placed into the linked list
193 * Its intrusive list links will be updated.
195 virtual void appendToList(std::lock_guard<std::mutex>& seqLock,
196 OrderedStoredValue& v) = 0;
199 * If possible, update an existing element the list and move it to end.
200 * If there is a range read in the position of the element being updated
201 * we do not allow the update and indicate the caller to do an append.
203 * @param seqLock A sequence lock the calling module is expected to hold.
204 * @param v Ref to orderedStoredValue which will placed into the linked list
205 * Its intrusive list links will be updated.
207 * @return UpdateStatus::Success list element has been updated and moved to
209 * UpdateStatus::Append list element is *not* updated. Caller must
212 virtual SequenceList::UpdateStatus updateListElem(
213 std::lock_guard<std::mutex>& seqLock, OrderedStoredValue& v) = 0;
216 * Provides point-in-time snapshots which can be used for incremental
219 * Copies the StoredValues as a vector of ref counterd items starting from
220 * 'start + 1' seqno into 'items' as a snapshot.
222 * Since we use monotonically increasing point-in-time snapshots we cannot
223 * guarantee that the snapshot ends at the requested end seqno. Due to
224 * dedups we may have to send till a higher seqno in the snapshot.
226 * @param start requested start seqno
227 * @param end requested end seqno
229 * @return ENGINE_SUCCESS, items in the snapshot and adjusted endSeqNo
230 * ENGINE_ENOMEM on no memory to copy items
231 * ENGINE_ERANGE on incorrect start and end
233 virtual std::tuple<ENGINE_ERROR_CODE, std::vector<UniqueItemPtr>, seqno_t>
234 rangeRead(seqno_t start, seqno_t end) = 0;
237 * Updates the highSeqno in the list. Since seqno is generated and managed
238 * outside the list, the module managing it must update this after the seqno
239 * is generated for the item already put in the list.
240 * @param highSeqnoLock The lock protecting the high seqnos the caller is
242 * @param v Ref to orderedStoredValue
244 virtual void updateHighSeqno(std::lock_guard<std::mutex>& highSeqnoLock,
245 const OrderedStoredValue& v) = 0;
248 * Updates the highestDedupedSeqno in the list. Since seqno is generated and
249 * managed outside the list, the module managing it must update this after
250 * the seqno is generated for the item already put in the list.
251 * @param highSeqnoLock The lock protecting the high seqnos the caller is
253 * @param v Ref to orderedStoredValue
256 virtual void updateHighestDedupedSeqno(
257 std::lock_guard<std::mutex>& highSeqnoLock,
258 const OrderedStoredValue& v) = 0;
261 * Mark an OrderedStoredValue stale and assumes its ownership.
262 * Note: It is upto the sequential data structure implementation how it
263 * wants to own the OrderedStoredValue (as owned type vs non-owned
266 * @param ownedSv StoredValue whose ownership is passed to the sequential
269 virtual void markItemStale(StoredValue::UniquePtr ownedSv) = 0;
272 * Remove from sequence list and delete all OSVs which are purgable.
273 * OSVs which can be purged are items which are outside the ReadRange and
276 * @return The number of items purged from the sequence list (and hence
279 virtual size_t purgeTombstones() = 0;
282 * Updates the number of deleted items in the sequence list whenever
283 * an item is modified.
285 * @param oldDeleted Was the old item deleted?
286 * @param newDeleted Was the new item replacing it deleted?
288 virtual void updateNumDeletedItems(bool oldDeleted, bool newDeleted) = 0;
291 * Returns the number of stale items in the list.
293 * @return count of stale items
295 virtual uint64_t getNumStaleItems() const = 0;
298 * Return the count of bytes of the values of stale items in the list.
300 virtual size_t getStaleValueBytes() const = 0;
303 * Return the count of bytes of the metadata of stale items in the list.
305 virtual size_t getStaleMetadataBytes() const = 0;
308 * Returns the number of deleted items in the list.
310 * @return count of deleted items
312 virtual uint64_t getNumDeletedItems() const = 0;
315 * Returns the number of items in the list.
317 * @return count of items
319 virtual uint64_t getNumItems() const = 0;
322 * Returns the highSeqno in the list.
324 virtual uint64_t getHighSeqno() const = 0;
327 * Returns the highest de-duplicated sequence number in the list.
329 virtual uint64_t getHighestDedupedSeqno() const = 0;
332 * Returns the highest purged Deleted sequence number in the list.
334 virtual seqno_t getHighestPurgedDeletedSeqno() const = 0;
337 * Returns the current range read begin sequence number.
339 virtual uint64_t getRangeReadBegin() const = 0;
342 * Returns the current range read end sequence number.
344 virtual uint64_t getRangeReadEnd() const = 0;
347 * Returns the lock which must be held to modify the highSeqno or the
348 * highestDedupedSeqno
350 virtual std::mutex& getHighSeqnosLock() const = 0;
353 * Returns a range iterator for the underlying SequenceList obj
355 virtual SequenceList::RangeIterator makeRangeIterator() = 0;
358 * Debug - prints a representation of the list to stderr.
360 virtual void dump() const = 0;