aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/datastore/unique_store_string_allocator.h
blob: be5fa8f6c1e43f78c2da31ecc0a6105e08c68c0d (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
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include "datastore.h"
#include "entryref.h"
#include "unique_store_add_result.h"
#include "unique_store_entry.h"
#include "i_compactable.h"
#include <cassert>
#include <string>

namespace vespalib::alloc { class MemoryAllocator; }

namespace vespalib::datastore {

namespace string_allocator {

extern std::vector<size_t> array_sizes;
uint32_t get_type_id(size_t string_len);

};

/*
 * Entry type for small strings. array_size is passed to constructors and
 * clean_hold to tell how many bytes are set aside for the entry.
 * array_size is supposed to be > sizeof(UniqueStoreSmallStringEntry).
 *
 * Class is trivially destructable, i.e. no need to call destructor.
 * Class is trivially copyable, i.e. memcpy can be used to make a copy.
 */
class UniqueStoreSmallStringEntry : public UniqueStoreEntryBase {
    char _value[0];
public:
    constexpr UniqueStoreSmallStringEntry()
        : UniqueStoreEntryBase(),
          _value()
    { }
    
    UniqueStoreSmallStringEntry(const char *value, size_t value_len, size_t array_size)
        : UniqueStoreEntryBase()
    {
        assert(value_offset() + value_len < array_size);
        memcpy(&_value[0], value, value_len);
        memset(&_value[0] + value_len, 0, array_size - value_len - value_offset());
    }

    void clean_hold(size_t array_size) {
        memset(&_value[0], 0, array_size - value_offset());
    }

    const char *value() const { return &_value[0]; }
    size_t value_offset() const { return &_value[0] - reinterpret_cast<const char *>(this); }
};

/*
 * Buffer type for small strings in unique store. Each entry uses array_size
 * bytes
 */
class UniqueStoreSmallStringBufferType : public BufferType<char> {
    std::shared_ptr<vespalib::alloc::MemoryAllocator> _memory_allocator;
public:
    UniqueStoreSmallStringBufferType(uint32_t array_size, uint32_t max_arrays, std::shared_ptr<vespalib::alloc::MemoryAllocator> memory_allocator);
    ~UniqueStoreSmallStringBufferType() override;
    void destroyElements(void *, ElemCount) override;
    void fallbackCopy(void *newBuffer, const void *oldBuffer, ElemCount numElems) override;
    void cleanHold(void *buffer, size_t offset, ElemCount numElems, CleanContext) override;
    const vespalib::alloc::MemoryAllocator* get_memory_allocator() const override;
};

/*
 * Buffer type for external strings in unique store.
 */
class UniqueStoreExternalStringBufferType : public BufferType<UniqueStoreEntry<std::string>> {
    std::shared_ptr<vespalib::alloc::MemoryAllocator> _memory_allocator;
public:
    UniqueStoreExternalStringBufferType(uint32_t array_size, uint32_t max_arrays, std::shared_ptr<vespalib::alloc::MemoryAllocator> memory_allocator);
    ~UniqueStoreExternalStringBufferType() override;
    void cleanHold(void *buffer, size_t offset, ElemCount numElems, CleanContext cleanCtx) override;
    const vespalib::alloc::MemoryAllocator* get_memory_allocator() const override;
};

/**
 * Allocator for unique NUL-terminated strings that is accessed via a
 * 32-bit EntryRef. Multiple buffer types are used. Small strings use
 * a common buffer type handler with different parameters for array
 * size (which denotes number of bytes set aside for meta data
 * (reference count), string and NUL byte. Large strings use a
 * different buffer type handler where buffer contains meta data
 * (reference count) and an std::string, while the string value is on
 * the heap.  string_allocator::get_type_id() is used to map from
 * string length to type id.
 */
template <typename RefT = EntryRefT<22> >
class UniqueStoreStringAllocator : public ICompactable
{
public:
    using DataStoreType = DataStoreT<RefT>;
    using EntryType = const char *;
    using EntryConstRefType = const char *;
    using WrappedExternalEntryType = UniqueStoreEntry<std::string>;
    using RefType = RefT;
private:
    DataStoreType _store;
    std::vector<std::unique_ptr<BufferTypeBase>> _type_handlers;

    static uint32_t get_type_id(const char *value);

public:
    UniqueStoreStringAllocator(std::shared_ptr<alloc::MemoryAllocator> memory_allocator);
    ~UniqueStoreStringAllocator() override;
    EntryRef allocate(const char *value);
    void hold(EntryRef ref);
    EntryRef move(EntryRef ref) override;
    const UniqueStoreEntryBase& get_wrapped(EntryRef ref) const {
        RefType iRef(ref);
        auto &state = _store.getBufferState(iRef.bufferId());
        auto type_id = state.getTypeId();
        if (type_id != 0) {
            return *reinterpret_cast<const UniqueStoreEntryBase *>(_store.template getEntryArray<char>(iRef, state.getArraySize()));
        } else {
            return *_store.template getEntry<WrappedExternalEntryType>(iRef);
        }
    }
    const char *get(EntryRef ref) const {
        RefType iRef(ref);
        auto &state = _store.getBufferState(iRef.bufferId());
        auto type_id = state.getTypeId();
        if (type_id != 0) {
            return reinterpret_cast<const UniqueStoreSmallStringEntry *>(_store.template getEntryArray<char>(iRef, state.getArraySize()))->value();
        } else {
            return _store.template getEntry<WrappedExternalEntryType>(iRef)->value().c_str();
        }
    }
    DataStoreType& get_data_store() { return _store; }
    const DataStoreType& get_data_store() const { return _store; }
};

extern template class BufferType<UniqueStoreEntry<std::string> >;

}