aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/vespa/searchlib/predicate/predicate_interval_store.h
blob: ca28c2d7e0b54bf97deaa7af41b2a25b0414d00b (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
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include "predicate_ref_cache.h"
#include <vespa/vespalib/datastore/bufferstate.h>
#include <vespa/vespalib/datastore/datastore.h>
#include <vector>

namespace search::predicate {
struct Interval;

/**
 * Stores interval entries in a memory-efficient way.
 * It works with both Interval and IntervalWithBounds entries.
 */
class PredicateIntervalStore {
    class DataStoreAdapter;
    using RefCacheType = PredicateRefCache<DataStoreAdapter, 8>;
    using DataStoreType = vespalib::datastore::DataStoreT<vespalib::datastore::EntryRefT<18, 6>>;
    using RefType =  DataStoreType::RefType;
    using generation_t = vespalib::GenerationHandler::generation_t;

    DataStoreType _store;
    vespalib::datastore::BufferType<uint32_t> _size1Type;

    class DataStoreAdapter {
        const DataStoreType &_store;
    public:
        DataStoreAdapter(const DataStoreType &store) : _store(store) {}
        const uint32_t *getBuffer(uint32_t ref) const {
            RefType entry_ref = vespalib::datastore::EntryRef(ref);
            return _store.getEntry<uint32_t>(entry_ref);
        }
    };
    DataStoreAdapter _store_adapter;
    RefCacheType     _ref_cache;

    // Return type for private allocation functions
    template <typename T>
    struct Entry {
        RefType ref;
        T *buffer;
    };

    // Allocates a new entry in a datastore buffer.
    template <typename T>
    Entry<T> allocNewEntry(uint32_t type_id, uint32_t size);
    // Returns the size of an interval entry in number of uint32_t.
    template <typename IntervalT>
    static uint32_t entrySize() { return sizeof(IntervalT) / sizeof(uint32_t); }

public:
    PredicateIntervalStore();
    ~PredicateIntervalStore();

    /**
     * Inserts an array of intervals into the store.
     * IntervalT is either Interval or IntervalWithBounds.
     */
    template <typename IntervalT>
    vespalib::datastore::EntryRef insert(const std::vector<IntervalT> &intervals);

    /**
     * Removes an entry. The entry remains accessible until commit
     * is called, and also as long as readers hold the current
     * generation.
     *
     * Remove is currently disabled, as the ref cache is assumed to
     * keep the total number of different entries low.
     */
    void remove(vespalib::datastore::EntryRef ref);

    void reclaim_memory(generation_t oldest_used_gen);

    void assign_generation(generation_t current_gen);

    /**
     * Return memory usage (only the data store is included)
     */
    vespalib::MemoryUsage getMemoryUsage() const {
        return _store.getMemoryUsage();
    }

    /**
     * Retrieves a list of intervals.
     * IntervalT is either Interval or IntervalWithBounds.
     * single_buf is a pointer to a single IntervalT, used by the
     * single interval optimization.
     */
    template <typename IntervalT>
    const IntervalT
    *get(vespalib::datastore::EntryRef btree_ref, uint32_t &size_out, IntervalT *single_buf) const
    {
        uint32_t size = btree_ref.ref() >> RefCacheType::SIZE_SHIFT;
        RefType data_ref(vespalib::datastore::EntryRef(btree_ref.ref() & RefCacheType::DATA_REF_MASK));
        if (__builtin_expect(size == 0, true)) {  // single-interval optimization
            *single_buf = IntervalT();
            single_buf->interval = data_ref.ref();
            size_out = 1;
            return single_buf;
        }
        const uint32_t *buf = _store.getEntry<uint32_t>(data_ref);
        if (size == RefCacheType::MAX_SIZE) {
            size = *buf++;
        }
        size_out = size / entrySize<IntervalT>();
        return reinterpret_cast<const IntervalT *>(buf);
    }
};

}