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
|
/*
* include/framework/structure/BufferView.h
*
* Copyright (C) 2023-2025 Douglas B. Rumbaugh <drumbaugh@psu.edu>
*
* Distributed under the Modified BSD License.
*
* TODO: This file is very poorly commented.
*/
#pragma once
#include <cassert>
#include <cstdlib>
#include <functional>
#include <utility>
#include "framework/interface/Record.h"
#include "psu-ds/BloomFilter.h"
#include "psu-util/alignment.h"
namespace de {
template <RecordInterface R> class BufferView {
public:
BufferView() = default;
/*
* the BufferView's lifetime is tightly linked to buffer versioning, 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_head(std::exchange(other.m_head, 0)),
m_tail(std::exchange(other.m_tail, 0)),
m_start(std::exchange(other.m_start, 0)),
m_stop(std::exchange(other.m_stop, 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)),
m_active(std::exchange(other.m_active, false)) {}
BufferView &operator=(BufferView &&other) = delete;
BufferView(Wrapped<R> *buffer, size_t cap, size_t head, size_t tail,
size_t tombstone_cnt, psudb::BloomFilter<R> *filter)
: m_data(buffer), m_head(head), m_tail(tail), m_start(m_head % cap),
m_stop(m_tail % cap), m_cap(cap), m_approx_ts_cnt(tombstone_cnt),
m_tombstone_filter(filter), m_active(true) {}
~BufferView() = default;
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) {
if (m_start < m_stop) {
for (size_t i = m_start; i < m_stop; i++) {
if (m_data[i].rec == rec) {
m_data[i].set_delete();
return true;
}
}
} else {
for (size_t i = m_start; i < m_cap; i++) {
if (m_data[i].rec == rec) {
m_data[i].set_delete();
return true;
}
}
for (size_t i = 0; i < m_stop; i++) {
if (m_data[i].rec == rec) {
m_data[i].set_delete();
return true;
}
}
}
return false;
}
size_t get_record_count() { return m_tail - m_head; }
size_t get_capacity() { return m_cap; }
/*
* 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) { return m_data + to_idx(i); }
void copy_to_buffer(psudb::byte *buffer) {
/* check if the region to be copied circles back to start. If so, do it in
* two steps */
if (m_start > m_stop) {
size_t split_idx = m_cap - m_start;
memcpy(buffer, (std::byte *)(m_data + m_start),
split_idx * sizeof(Wrapped<R>));
memcpy(buffer + (split_idx * sizeof(Wrapped<R>)), (std::byte *)m_data,
m_stop * sizeof(Wrapped<R>));
} else {
memcpy(buffer, (std::byte *)(m_data + m_start),
get_record_count() * sizeof(Wrapped<R>));
}
}
size_t get_tail() { return m_tail; }
size_t get_head() { return m_head; }
private:
Wrapped<R> *m_data;
size_t m_head;
size_t m_tail;
size_t m_start;
size_t m_stop;
size_t m_cap;
size_t m_approx_ts_cnt;
psudb::BloomFilter<R> *m_tombstone_filter;
bool m_active;
size_t to_idx(size_t i) {
size_t idx = (m_start + i >= m_cap) ? i - (m_cap - m_start) : m_start + i;
assert(idx < m_cap);
return idx;
}
};
} // namespace de
|