aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/btree/btreestore.h
blob: 7dd839f15293f59cbe7498bba6c1780974fa5716 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include "btreenode.h"
#include "btreebuilder.h"
#include "btreeroot.h"
#include "noaggrcalc.h"
#include "minmaxaggrcalc.h"
#include <vespa/vespalib/datastore/datastore.h>
#include <vespa/vespalib/datastore/handle.h>

namespace vespalib::btree {

template <typename KeyT,
          typename DataT,
          typename AggrT,
          typename CompareT,
          typename TraitsT,
          typename AggrCalcT = NoAggrCalc>
class BTreeStore
{
public:
    using KeyType = KeyT;
    using DataType = DataT;
    using AggregatedType = AggrT;
    using DataStoreType = datastore::DataStoreT<datastore::EntryRefT<22> >;
    using RefType = DataStoreType::RefType;
    using KeyDataType = BTreeKeyData<KeyT, DataT>;

    using BTreeType = BTreeRoot<KeyT, DataT, AggrT, CompareT, TraitsT, AggrCalcT>;
    using InternalNodeType = BTreeInternalNode<KeyT, AggrT, TraitsT::INTERNAL_SLOTS>;
    using LeafNodeType = BTreeLeafNode<KeyT, DataT, AggrT, TraitsT::LEAF_SLOTS>;
    using BTreeTypeRefPair = datastore::Handle<BTreeType>;
    using KeyDataTypeRefPair = datastore::Handle<KeyDataType>;
    using InternalNodeTypeRefPair = typename InternalNodeType::RefPair;
    using LeafNodeTypeRefPair = typename LeafNodeType::RefPair;
    using generation_t = vespalib::GenerationHandler::generation_t;
    using NodeAllocatorType = BTreeNodeAllocator<KeyT, DataT, AggrT,
                                                 TraitsT::INTERNAL_SLOTS,
                                                 TraitsT::LEAF_SLOTS>;
    using Iterator = typename BTreeType::Iterator;
    using ConstIterator = typename BTreeType::ConstIterator;
    using AddIter = const KeyDataType *;
    using RemoveIter = const KeyType *;
    using Builder = BTreeBuilder<KeyT, DataT, AggrT,
                                 TraitsT::INTERNAL_SLOTS,
                                 TraitsT::LEAF_SLOTS,
                                 AggrCalcT>;
    using CompactionSpec = datastore::CompactionSpec;
    using CompactionStrategy = datastore::CompactionStrategy;
    using EntryRef = datastore::EntryRef;
    template <typename ElemT>
    using BufferType = datastore::BufferType<ElemT>;
    using BufferState = datastore::BufferState;

    static constexpr uint32_t clusterLimit = 8;

    enum BufferTypes
    {
        BUFFERTYPE_ARRAY1 = 0,
        BUFFERTYPE_ARRAY2 = 1,
        BUFFERTYPE_ARRAY3 = 2,
        BUFFERTYPE_ARRAY4 = 3,
        BUFFERTYPE_ARRAY5 = 4,
        BUFFERTYPE_ARRAY6 = 5,
        BUFFERTYPE_ARRAY7 = 6,
        BUFFERTYPE_ARRAY8 = 7,
        BUFFERTYPE_BTREE = 8
    };
protected:
    struct TreeReclaimer {
        static void reclaim(BTreeType * tree) {
            tree->recycle();
        }
    };

    DataStoreType _store;
    BufferType<BTreeType> _treeType;
    BufferType<KeyDataType> _small1Type;
    BufferType<KeyDataType> _small2Type;
    BufferType<KeyDataType> _small3Type;
    BufferType<KeyDataType> _small4Type;
    BufferType<KeyDataType> _small5Type;
    BufferType<KeyDataType> _small6Type;
    BufferType<KeyDataType> _small7Type;
    BufferType<KeyDataType> _small8Type;
    NodeAllocatorType _allocator;
    AggrCalcT _aggrCalc;
    Builder _builder;

    BTreeType * getWTreeEntry(RefType ref) {
        return _store.getEntry<BTreeType>(ref);
    }

public:
    BTreeStore();
    BTreeStore(bool init);
    ~BTreeStore();

    const NodeAllocatorType &getAllocator() const { return _allocator; }

    void disableFreeLists() {
        _store.disableFreeLists();
        _allocator.disableFreeLists();
    }

    void disable_entry_hold_list() {
        _store.disable_entry_hold_list();
        _allocator.disable_entry_hold_list();
    }

    BTreeTypeRefPair allocNewBTree() {
        return _store.allocator<BTreeType>(BUFFERTYPE_BTREE).alloc();
    }

    BTreeTypeRefPair allocBTree() {
        return _store.freeListAllocator<BTreeType, TreeReclaimer>(BUFFERTYPE_BTREE).alloc();
    }

    BTreeTypeRefPair allocNewBTreeCopy(const BTreeType &rhs) {
        return _store.allocator<BTreeType>(BUFFERTYPE_BTREE).alloc(rhs);
    }

    BTreeTypeRefPair allocBTreeCopy(const BTreeType &rhs) {
        return _store.freeListAllocator<BTreeType, datastore::DefaultReclaimer<BTreeType> >(BUFFERTYPE_BTREE).alloc(rhs);
    }

    KeyDataTypeRefPair allocNewKeyData(uint32_t clusterSize);
    KeyDataTypeRefPair allocKeyData(uint32_t clusterSize);
    KeyDataTypeRefPair allocNewKeyDataCopy(const KeyDataType *rhs, uint32_t clusterSize);
    KeyDataTypeRefPair allocKeyDataCopy(const KeyDataType *rhs, uint32_t clusterSize);

    const KeyDataType * lower_bound(const KeyDataType *b, const KeyDataType *e, const KeyType &key, CompareT comp);

    void makeTree(EntryRef &ref, const KeyDataType *array, uint32_t clusterSize);
    void makeArray(EntryRef &ref, EntryRef leafRef, LeafNodeType *leafNode);
    bool insert(EntryRef &ref, const KeyType &key, const DataType &data, CompareT comp = CompareT());

    bool remove(EntryRef &ref, const KeyType &key,CompareT comp = CompareT());

    uint32_t getNewClusterSize(const KeyDataType *o, const KeyDataType *oe, AddIter a, AddIter ae,
                               RemoveIter r, RemoveIter re, CompareT comp);

    void applyCluster(const KeyDataType *o, const KeyDataType *oe, KeyDataType *d, const KeyDataType *de,
                      AddIter a, AddIter ae, RemoveIter r, RemoveIter re, CompareT comp);

    void applyModifyTree(BTreeType *tree, AddIter a, AddIter ae, RemoveIter r, RemoveIter re, CompareT comp);
    void applyBuildTree(BTreeType *tree, AddIter a, AddIter ae, RemoveIter r, RemoveIter re, CompareT comp);
    void applyNewArray(EntryRef &ref, AddIter aOrg, AddIter ae);
    void applyNewTree(EntryRef &ref, AddIter a, AddIter ae, CompareT comp);
    void applyNew(EntryRef &ref, AddIter a, AddIter ae, CompareT comp);

    bool applyCluster(EntryRef &ref, uint32_t clusterSize, AddIter a, AddIter ae,
                      RemoveIter r, RemoveIter re, CompareT comp);

    void applyTree(BTreeType *tree, AddIter a, AddIter ae, RemoveIter r, RemoveIter re, CompareT comp);

    void normalizeTree(EntryRef &ref, BTreeType *tree, bool wasArray);
    /**
     * Apply multiple changes at once.
     *
     * additions and removals should be sorted on key without duplicates.
     * Overlap between additions and removals indicates updates.
     */
    void apply(EntryRef &ref, AddIter a, AddIter ae, RemoveIter r, RemoveIter re, CompareT comp = CompareT());

    void clear(const EntryRef ref);
    size_t size(const EntryRef ref) const;
    size_t frozenSize(const EntryRef ref) const;
    Iterator begin(const EntryRef ref) const;
    ConstIterator beginFrozen(const EntryRef ref) const;

    void beginFrozen(const EntryRef ref, std::vector<ConstIterator> &where) const;

    uint32_t getTypeId(RefType ref) const {
        return _store.getBufferMeta(ref.bufferId()).getTypeId();
    }

    static bool isSmallArray(uint32_t typeId) { return typeId < clusterLimit; }
    bool isSmallArray(const EntryRef ref) const;
    static bool isBTree(uint32_t typeId) { return typeId == BUFFERTYPE_BTREE; }
    bool isBTree(RefType ref) const { return isBTree(getTypeId(ref)); }

    /**
     * Returns the cluster size for the type id.
     * Cluster size == 0 means we have a tree for the given reference.
     * The reference must be valid.
     **/
    static uint32_t getClusterSize(uint32_t typeId) {
        return (typeId < clusterLimit) ? typeId + 1 : 0;
    }

    /**
     * Returns the cluster size for the entry pointed to by the given reference.
     * Cluster size == 0 means we have a tree for the given reference.
     * The reference must be valid.
     **/
    uint32_t getClusterSize(RefType ref) const { return getClusterSize(getTypeId(ref)); }

    const BTreeType * getTreeEntry(RefType ref) const {
        return _store.getEntry<BTreeType>(ref);
    }

    const KeyDataType * getKeyDataEntry(RefType ref, uint32_t arraySize) const {
        return _store.getEntryArray<KeyDataType>(ref, arraySize);
    }

    void freeze() {
        _allocator.freeze();
    }

    // Inherit doc from DataStoreBase
    void reclaim_memory(generation_t oldest_used_gen) {
        _allocator.reclaim_memory(oldest_used_gen);
        _store.reclaim_memory(oldest_used_gen);
    }

    // Inherit doc from DataStoreBase
    void assign_generation(generation_t current_gen) {
        _allocator.assign_generation(current_gen);
        _store.assign_generation(current_gen);
    }

    void reclaim_all_memory() {
        _allocator.reclaim_all_memory();
        _store.reclaim_all_memory();
    }


    // Inherit doc from DataStoreBase
    vespalib::MemoryUsage getMemoryUsage() const {
        vespalib::MemoryUsage usage;
        usage.merge(_allocator.getMemoryUsage());
        usage.merge(_store.getMemoryUsage());
        return usage;
    }

    void clearBuilder() {
        _builder.clear();
    }

    AggregatedType getAggregated(const EntryRef ref) const;

    template <typename FunctionType>
    void foreach_unfrozen_key(EntryRef ref, FunctionType func) const;

    template <typename FunctionType>
    void foreach_frozen_key(EntryRef ref, FunctionType func) const;

    template <typename FunctionType>
    void foreach_unfrozen(EntryRef ref, FunctionType func) const;

    template <typename FunctionType>
    void foreach_frozen(EntryRef ref, FunctionType func) const;

    std::unique_ptr<vespalib::datastore::CompactingBuffers> start_compact_worst_btree_nodes(const CompactionStrategy& compaction_strategy);
    void move_btree_nodes(const std::vector<EntryRef>& refs);

    std::unique_ptr<vespalib::datastore::CompactingBuffers> start_compact_worst_buffers(CompactionSpec compaction_spec, const CompactionStrategy& compaction_strategy);
    void move(std::vector<EntryRef>& refs);

private:
    static constexpr size_t MIN_BUFFER_ARRAYS = 128u;
    template <typename FunctionType, bool Frozen>
    void foreach_key(EntryRef ref, FunctionType func) const;

    template <typename FunctionType, bool Frozen>
    void foreach(EntryRef ref, FunctionType func) const;
};

template <typename KeyT, typename DataT, typename AggrT, typename CompareT,
          typename TraitsT, typename AggrCalcT>
template <typename FunctionType>
void
BTreeStore<KeyT, DataT, AggrT, CompareT, TraitsT, AggrCalcT>::
foreach_unfrozen_key(EntryRef ref, FunctionType func) const {
    foreach_key<FunctionType, false>(ref, func);
}

template <typename KeyT, typename DataT, typename AggrT, typename CompareT,
          typename TraitsT, typename AggrCalcT>
template <typename FunctionType>
void
BTreeStore<KeyT, DataT, AggrT, CompareT, TraitsT, AggrCalcT>::
foreach_frozen_key(EntryRef ref, FunctionType func) const
{
    foreach_key<FunctionType, true>(ref, func);
}

template <typename KeyT, typename DataT, typename AggrT, typename CompareT,
        typename TraitsT, typename AggrCalcT>
template <typename FunctionType>
void
BTreeStore<KeyT, DataT, AggrT, CompareT, TraitsT, AggrCalcT>::
foreach_unfrozen(EntryRef ref, FunctionType func) const
{
    foreach<FunctionType, false>(ref, func);
}


template <typename KeyT, typename DataT, typename AggrT, typename CompareT,
          typename TraitsT, typename AggrCalcT>
template <typename FunctionType>
void
BTreeStore<KeyT, DataT, AggrT, CompareT, TraitsT, AggrCalcT>::
foreach_frozen(EntryRef ref, FunctionType func) const
{
    foreach<FunctionType, true>(ref, func);
}

template <typename KeyT, typename DataT, typename AggrT, typename CompareT,
        typename TraitsT, typename AggrCalcT>
template <typename FunctionType, bool Frozen>
void
BTreeStore<KeyT, DataT, AggrT, CompareT, TraitsT, AggrCalcT>::
foreach_key(EntryRef ref, FunctionType func) const
{
    if (!ref.valid())
        return;
    RefType iRef(ref);
    uint32_t clusterSize = getClusterSize(iRef);
    if (clusterSize == 0) {
        const BTreeType *tree = getTreeEntry(iRef);
        _allocator.getNodeStore().foreach_key(Frozen ? tree->getFrozenRoot() : tree->getRoot(), func);
    } else {
        const KeyDataType *p = getKeyDataEntry(iRef, clusterSize);
        const KeyDataType *pe = p + clusterSize;
        for (; p != pe; ++p) {
            func(p->_key);
        }
    }
}

template <typename KeyT, typename DataT, typename AggrT, typename CompareT,
          typename TraitsT, typename AggrCalcT>
template <typename FunctionType, bool Frozen>
void
BTreeStore<KeyT, DataT, AggrT, CompareT, TraitsT, AggrCalcT>::
foreach(EntryRef ref, FunctionType func) const
{
    if (!ref.valid())
        return;
    RefType iRef(ref);
    uint32_t clusterSize = getClusterSize(iRef);
    if (clusterSize == 0) {
        const BTreeType *tree = getTreeEntry(iRef);
        _allocator.getNodeStore().foreach(Frozen ? tree->getFrozenRoot() : tree->getRoot(), func);
    } else {
        const KeyDataType *p = getKeyDataEntry(iRef, clusterSize);
        const KeyDataType *pe = p + clusterSize;
        for (; p != pe; ++p) {
            func(p->_key, p->getData());
        }
    }
}


extern template class BTreeStore<uint32_t, uint32_t,
                                 NoAggregated,
                                 std::less<uint32_t>,
                                 BTreeDefaultTraits>;

extern template class BTreeStore<uint32_t, BTreeNoLeafData,
                                 NoAggregated,
                                 std::less<uint32_t>,
                                 BTreeDefaultTraits>;

extern template class BTreeStore<uint32_t, int32_t,
                                 MinMaxAggregated,
                                 std::less<uint32_t>,
                                 BTreeDefaultTraits,
                                 MinMaxAggrCalc>;

}

namespace vespalib::datastore {

using namespace btree;

extern template class BufferType<BTreeRoot<uint32_t, uint32_t, NoAggregated, std::less<uint32_t>, BTreeDefaultTraits>>;
extern template class BufferType<BTreeRoot<uint32_t, BTreeNoLeafData, NoAggregated, std::less<uint32_t>, BTreeDefaultTraits>>;
extern template class BufferType<BTreeRoot<uint32_t, int32_t, MinMaxAggregated, std::less<uint32_t>, BTreeDefaultTraits, MinMaxAggrCalc>>;

extern template class BufferType<BTreeKeyData<uint32_t, uint32_t>>;
extern template class BufferType<BTreeKeyData<uint32_t, int32_t>>;
extern template class BufferType<BTreeKeyData<uint32_t, BTreeNoLeafData>>;

}