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
|
/*
* include/framework/structure/BufferView.h
*
* Copyright (C) 2023 Douglas B. Rumbaugh <drumbaugh@psu.edu>
*
* Distributed under the Modified BSD License.
*
*/
#pragma once
#include <cstdlib>
#include <cassert>
#include <functional>
#include "psu-util/alignment.h"
#include "psu-ds/BloomFilter.h"
#include "framework/interface/Record.h"
namespace de {
typedef std::_Bind<void (*(void*, long unsigned int))(void*, long unsigned int)> ReleaseFunction;
static void noop_func(void *arg1, size_t arg2) {
return;
}
constexpr auto noop_bind = std::bind(noop_func, (void*) nullptr, 0ul);
template <RecordInterface R>
class BufferView {
public:
BufferView()
: m_data(nullptr)
, m_release(noop_bind)
, m_head(0)
, m_tail(0)
, m_cap(0)
, m_approx_ts_cnt(0)
, m_tombstone_filter(nullptr) {}
/*
* the BufferView's lifetime is tightly linked to buffer versioning, and so
* copying and assignment are disabled.
*/
BufferView(const BufferView&) = delete;
BufferView &operator=(BufferView &) = delete;
BufferView(BufferView &&other)
: m_data(std::exchange(other.m_data, nullptr))
, m_release(std::move(other.m_release))
, m_head(std::exchange(other.m_head, 0))
, m_tail(std::exchange(other.m_tail, 0))
, m_cap(std::exchange(other.m_cap, 0))
, m_approx_ts_cnt(std::exchange(other.m_approx_ts_cnt, 0))
, m_tombstone_filter(std::exchange(other.m_tombstone_filter, nullptr)) {}
BufferView &operator=(BufferView &&other) noexcept {
std::swap(m_data, other.m_data);
m_release = std::move(other.m_release);
std::swap(m_head, other.m_head);
std::swap(m_tail, other.m_tail);
std::swap(m_cap, other.m_cap);
std::swap(m_approx_ts_cnt, other.m_approx_ts_cnt);
std::swap(m_tombstone_filter, other.m_tombstone_filter);
return *this;
}
BufferView(Wrapped<R> *buffer, size_t cap, size_t head, size_t tail, size_t tombstone_cnt, psudb::BloomFilter<R> *filter,
ReleaseFunction release)
: m_data(buffer)
, m_release(release)
, m_head(head)
, m_tail(tail)
, m_cap(cap)
, m_approx_ts_cnt(tombstone_cnt)
, m_tombstone_filter(filter) {}
~BufferView() {
m_release();
}
bool check_tombstone(const R& rec) {
if (m_tombstone_filter && !m_tombstone_filter->lookup(rec)) return false;
for (size_t i=0; i<get_record_count(); i++) {
if (m_data[to_idx(i)].rec == rec && m_data[to_idx(i)].is_tombstone()) {
return true;
}
}
return false;
}
bool delete_record(const R& rec) {
for (size_t i=0; i<get_record_count(); i++) {
if (m_data[to_idx(i)].rec == rec) {
m_data[to_idx(i)].set_delete();
return true;
}
}
return false;
}
size_t get_record_count() {
return m_tail - m_head;
}
/*
* NOTE: This function returns an upper bound on the number
* of tombstones within the view. There may be less than
* this, due to synchronization issues during view creation.
*/
size_t get_tombstone_count() {
return m_approx_ts_cnt;
}
Wrapped<R> *get(size_t i) {
assert(i < get_record_count());
return m_data + to_idx(i);
}
void copy_to_buffer(psudb::byte *buffer) {
memcpy(buffer, (std::byte*) (m_data + m_head), get_record_count() * sizeof(Wrapped<R>));
}
private:
Wrapped<R>* m_data;
ReleaseFunction m_release;
size_t m_head;
size_t m_tail;
size_t m_cap;
size_t m_approx_ts_cnt;
psudb::BloomFilter<R> *m_tombstone_filter;
size_t to_idx(size_t i) {
return (m_head + i) % m_cap;
}
};
}
|