Repository navigation
Expand file tree
/
Copy pathColumnFamily.java
More file actions
284 lines (262 loc) · 10.5 KB
/
Copy pathColumnFamily.java
File metadata and controls
284 lines (262 loc) · 10.5 KB
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
/**
*
* Copyright (C) TidesDB
*
* Original Author: Alex Gaetano Padula
*
* Licensed under the Mozilla Public License, v. 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.mozilla.org/en-US/MPL/2.0/
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.tidesdb;
/**
* Represents a column family in TidesDB.
* Column families are isolated key-value stores with independent configuration.
*/
public class ColumnFamily {
static {
NativeLibrary.load();
}
private final long nativeHandle;
private final String name;
private long commitHookCtxHandle = 0;
private final TidesDB owner;
ColumnFamily(long nativeHandle, String name) {
this(nativeHandle, name, null);
}
ColumnFamily(long nativeHandle, String name, TidesDB owner) {
this.nativeHandle = nativeHandle;
this.name = name;
this.owner = owner;
}
/**
* Checks that the owning database is open. Throws if the owner is closed.
*/
void checkOwnerOpen() {
if (owner != null && owner.isClosed()) {
throw new IllegalStateException("TidesDB instance is closed");
}
}
/**
* Gets the name of this column family.
*
* @return the column family name
*/
public String getName() {
return name;
}
/**
* Retrieves statistics about this column family.
*
* @return column family statistics
* @throws TidesDBException if the stats cannot be retrieved
*/
public Stats getStats() throws TidesDBException {
checkOwnerOpen();
return nativeGetStats(nativeHandle);
}
/**
* Manually triggers compaction for this column family.
*
* @throws TidesDBException if compaction fails
*/
public void compact() throws TidesDBException {
checkOwnerOpen();
nativeCompact(nativeHandle);
}
/**
* Synchronously compacts every SSTable whose key range overlaps {@code [startKey, endKey)}.
* Blocks the calling thread until the merge commits or fails - does not enqueue work
* onto the compaction thread pool.
*
* <p>A {@code null} or empty endpoint means unbounded on that side. Both endpoints
* being {@code null} or empty is rejected with {@link TidesDBException}; callers
* wanting full-CF compaction must use {@link #compact()}.</p>
*
* @param startKey lower bound of the range, or {@code null}/empty for unbounded
* @param endKey upper bound (exclusive), or {@code null}/empty for unbounded
* @throws TidesDBException if the range is invalid, another compaction is running,
* or the merge fails
*/
public void compactRange(byte[] startKey, byte[] endKey) throws TidesDBException {
checkOwnerOpen();
nativeCompactRange(nativeHandle, startKey, endKey);
}
/**
* Manually triggers memtable flush for this column family.
*
* @throws TidesDBException if flush fails
*/
public void flushMemtable() throws TidesDBException {
checkOwnerOpen();
nativeFlushMemtable(nativeHandle);
}
/**
* Checks if a flush operation is currently in progress for this column family.
*
* @return true if flushing is in progress
*/
public boolean isFlushing() {
checkOwnerOpen();
return nativeIsFlushing(nativeHandle);
}
/**
* Checks if a compaction operation is currently in progress for this column family.
*
* @return true if compaction is in progress
*/
public boolean isCompacting() {
checkOwnerOpen();
return nativeIsCompacting(nativeHandle);
}
/**
* Updates runtime-safe configuration settings for this column family.
* Configuration changes are applied to new operations only.
*
* <p>Updatable settings (safe to change at runtime):</p>
* <ul>
* <li>writeBufferSize - Memtable flush threshold</li>
* <li>skipListMaxLevel - Skip list level for new memtables</li>
* <li>skipListProbability - Skip list probability for new memtables</li>
* <li>bloomFPR - False positive rate for new SSTables</li>
* <li>indexSampleRatio - Index sampling ratio for new SSTables</li>
* <li>syncMode - Durability mode</li>
* <li>syncIntervalUs - Sync interval in microseconds</li>
* </ul>
*
* @param config the new configuration
* @param persistToDisk if true, saves changes to config.ini
* @throws TidesDBException if the update fails
*/
public void updateRuntimeConfig(ColumnFamilyConfig config, boolean persistToDisk) throws TidesDBException {
checkOwnerOpen();
if (config == null) {
throw new IllegalArgumentException("Config cannot be null");
}
nativeUpdateRuntimeConfig(nativeHandle,
config.getWriteBufferSize(),
config.getSkipListMaxLevel(),
config.getSkipListProbability(),
config.getBloomFPR(),
config.getIndexSampleRatio(),
config.getSyncMode().getValue(),
config.getSyncIntervalUs(),
persistToDisk);
}
/**
* Forces a synchronous flush and aggressive compaction for this column family.
* Unlike {@link #compact()} and {@link #flushMemtable()} (which are non-blocking),
* purge blocks until all flush and compaction I/O is complete.
*
* @throws TidesDBException if the purge fails
*/
public void purge() throws TidesDBException {
checkOwnerOpen();
nativePurge(nativeHandle);
}
/**
* Forces an immediate fsync of the active write-ahead log for this column family.
* Useful for explicit durability control when using SYNC_NONE or SYNC_INTERVAL modes.
*
* @throws TidesDBException if the WAL sync fails
*/
public void syncWal() throws TidesDBException {
checkOwnerOpen();
nativeSyncWal(nativeHandle);
}
/**
* Estimates the computational cost of iterating between two keys in this column family.
* The returned value is an opaque double - meaningful only for comparison with other
* values from the same method. Uses only in-memory metadata and performs no disk I/O.
* Key order does not matter - the method normalizes the range internally.
*
* @param keyA first key (bound of range)
* @param keyB second key (bound of range)
* @return estimated traversal cost (higher = more expensive), 0.0 if no overlapping data
* @throws TidesDBException if the estimation fails
*/
public double rangeCost(byte[] keyA, byte[] keyB) throws TidesDBException {
checkOwnerOpen();
if (keyA == null || keyA.length == 0) {
throw new IllegalArgumentException("keyA cannot be null or empty");
}
if (keyB == null || keyB.length == 0) {
throw new IllegalArgumentException("keyB cannot be null or empty");
}
return nativeRangeCost(nativeHandle, keyA, keyB);
}
/**
* Sets a commit hook (Change Data Capture) for this column family.
* The hook fires synchronously after every transaction commit, receiving the full
* batch of committed operations atomically. Keep the callback fast to avoid
* stalling writers.
*
* <p>Hooks are runtime-only and not persisted. After a database restart,
* hooks must be re-registered by the application.</p>
*
* @param hook the commit hook callback
* @throws TidesDBException if the hook cannot be set
*/
public void setCommitHook(CommitHook hook) throws TidesDBException {
checkOwnerOpen();
if (hook == null) {
throw new IllegalArgumentException("Hook cannot be null, use clearCommitHook() instead");
}
boolean firstInstall = (commitHookCtxHandle == 0);
commitHookCtxHandle = nativeSetCommitHook(nativeHandle, hook, commitHookCtxHandle);
if (firstInstall && owner != null) {
owner.registerHookColumnFamily(this);
}
}
/**
* Clears the commit hook for this column family.
* After this call, no further commit callbacks will fire.
*
* @throws TidesDBException if the hook cannot be cleared
*/
public void clearCommitHook() throws TidesDBException {
checkOwnerOpen();
commitHookCtxHandle = nativeSetCommitHook(nativeHandle, null, commitHookCtxHandle);
if (owner != null) {
owner.unregisterHookColumnFamily(this);
}
}
/**
* Best-effort hook detach during database close. The hook is removed from
* the engine without caller interaction. Errors are swallowed.
*/
void clearHookOnClose() {
if (commitHookCtxHandle != 0) {
try {
nativeSetCommitHook(nativeHandle, null, commitHookCtxHandle);
} catch (TidesDBException ignored) {
// Best-effort during shutdown.
}
commitHookCtxHandle = 0;
}
}
long getNativeHandle() {
return nativeHandle;
}
private static native Stats nativeGetStats(long handle) throws TidesDBException;
private static native void nativeCompact(long handle) throws TidesDBException;
private static native void nativeCompactRange(long handle, byte[] startKey, byte[] endKey) throws TidesDBException;
private static native void nativeFlushMemtable(long handle) throws TidesDBException;
private static native boolean nativeIsFlushing(long handle);
private static native boolean nativeIsCompacting(long handle);
private static native void nativeUpdateRuntimeConfig(long handle, long writeBufferSize,
int skipListMaxLevel, float skipListProbability, double bloomFPR, int indexSampleRatio,
int syncMode, long syncIntervalUs, boolean persistToDisk) throws TidesDBException;
private static native double nativeRangeCost(long handle, byte[] keyA, byte[] keyB) throws TidesDBException;
private static native long nativeSetCommitHook(long handle, CommitHook hook, long oldCtxHandle) throws TidesDBException;
private static native void nativePurge(long handle) throws TidesDBException;
private static native void nativeSyncWal(long handle) throws TidesDBException;
}