slatedb 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Cargo.toml +9 -0
- data/LICENSE +176 -0
- data/README.md +404 -0
- data/ext/slatedb/Cargo.toml +22 -0
- data/ext/slatedb/extconf.rb +6 -0
- data/ext/slatedb/src/admin.rs +273 -0
- data/ext/slatedb/src/database.rs +457 -0
- data/ext/slatedb/src/errors.rs +144 -0
- data/ext/slatedb/src/iterator.rs +118 -0
- data/ext/slatedb/src/lib.rs +50 -0
- data/ext/slatedb/src/reader.rs +233 -0
- data/ext/slatedb/src/runtime.rs +78 -0
- data/ext/slatedb/src/snapshot.rs +197 -0
- data/ext/slatedb/src/transaction.rs +298 -0
- data/ext/slatedb/src/utils.rs +18 -0
- data/ext/slatedb/src/write_batch.rs +98 -0
- data/lib/slatedb/admin.rb +122 -0
- data/lib/slatedb/database.rb +310 -0
- data/lib/slatedb/iterator.rb +31 -0
- data/lib/slatedb/reader.rb +105 -0
- data/lib/slatedb/snapshot.rb +54 -0
- data/lib/slatedb/transaction.rb +78 -0
- data/lib/slatedb/version.rb +5 -0
- data/lib/slatedb/write_batch.rb +38 -0
- data/lib/slatedb.rb +20 -0
- metadata +140 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SlateDb
|
|
4
|
+
class Database
|
|
5
|
+
class << self
|
|
6
|
+
# Open a database at the given path.
|
|
7
|
+
#
|
|
8
|
+
# @param path [String] The path identifier for the database
|
|
9
|
+
# @param url [String, nil] Optional object store URL (e.g., "s3://bucket/path")
|
|
10
|
+
# @yield [db] If a block is given, yields the database and ensures it's closed
|
|
11
|
+
# @return [Database] The opened database (or block result if block given)
|
|
12
|
+
#
|
|
13
|
+
# @example Open a database
|
|
14
|
+
# db = SlateDb::Database.open("/tmp/mydb")
|
|
15
|
+
# db.put("key", "value")
|
|
16
|
+
# db.close
|
|
17
|
+
#
|
|
18
|
+
# @example Open with block (auto-close)
|
|
19
|
+
# SlateDb::Database.open("/tmp/mydb") do |db|
|
|
20
|
+
# db.put("key", "value")
|
|
21
|
+
# end # automatically closed
|
|
22
|
+
#
|
|
23
|
+
# @example Open with S3 backend
|
|
24
|
+
# db = SlateDb::Database.open("/tmp/mydb", url: "s3://mybucket/path")
|
|
25
|
+
#
|
|
26
|
+
def open(path, url: nil)
|
|
27
|
+
db = _open(path, url)
|
|
28
|
+
|
|
29
|
+
if block_given?
|
|
30
|
+
begin
|
|
31
|
+
yield db
|
|
32
|
+
ensure
|
|
33
|
+
begin
|
|
34
|
+
db.close
|
|
35
|
+
rescue StandardError
|
|
36
|
+
nil
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
else
|
|
40
|
+
db
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Get a value by key.
|
|
46
|
+
#
|
|
47
|
+
# @param key [String] The key to look up
|
|
48
|
+
# @param durability_filter [String, nil] Filter by durability level ("remote" or "memory")
|
|
49
|
+
# @param dirty [Boolean, nil] Whether to include uncommitted data
|
|
50
|
+
# @param cache_blocks [Boolean, nil] Whether to cache blocks
|
|
51
|
+
# @return [String, nil] The value, or nil if not found
|
|
52
|
+
#
|
|
53
|
+
# @example Basic get
|
|
54
|
+
# value = db.get("mykey")
|
|
55
|
+
#
|
|
56
|
+
# @example Get with options
|
|
57
|
+
# value = db.get("mykey", durability_filter: "memory", dirty: true)
|
|
58
|
+
#
|
|
59
|
+
def get(key, durability_filter: nil, dirty: nil, cache_blocks: nil)
|
|
60
|
+
opts = {}
|
|
61
|
+
opts[:durability_filter] = durability_filter.to_s if durability_filter
|
|
62
|
+
opts[:dirty] = dirty unless dirty.nil?
|
|
63
|
+
opts[:cache_blocks] = cache_blocks unless cache_blocks.nil?
|
|
64
|
+
|
|
65
|
+
if opts.empty?
|
|
66
|
+
_get(key)
|
|
67
|
+
else
|
|
68
|
+
_get_with_options(key, opts)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Store a key-value pair.
|
|
73
|
+
#
|
|
74
|
+
# @param key [String] The key to store
|
|
75
|
+
# @param value [String] The value to store
|
|
76
|
+
# @param ttl [Integer, nil] Time-to-live in milliseconds
|
|
77
|
+
# @param await_durable [Boolean] Whether to wait for durability (default: true)
|
|
78
|
+
# @return [void]
|
|
79
|
+
#
|
|
80
|
+
# @example Basic put
|
|
81
|
+
# db.put("mykey", "myvalue")
|
|
82
|
+
#
|
|
83
|
+
# @example Put with TTL
|
|
84
|
+
# db.put("mykey", "myvalue", ttl: 60_000) # expires in 60 seconds
|
|
85
|
+
#
|
|
86
|
+
# @example Put without waiting for durability
|
|
87
|
+
# db.put("mykey", "myvalue", await_durable: false)
|
|
88
|
+
#
|
|
89
|
+
def put(key, value, ttl: nil, await_durable: nil)
|
|
90
|
+
opts = {}
|
|
91
|
+
opts[:ttl] = ttl if ttl
|
|
92
|
+
opts[:await_durable] = await_durable unless await_durable.nil?
|
|
93
|
+
|
|
94
|
+
if opts.empty?
|
|
95
|
+
_put(key, value)
|
|
96
|
+
else
|
|
97
|
+
_put_with_options(key, value, opts)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Delete a key.
|
|
102
|
+
#
|
|
103
|
+
# @param key [String] The key to delete
|
|
104
|
+
# @param await_durable [Boolean] Whether to wait for durability (default: true)
|
|
105
|
+
# @return [void]
|
|
106
|
+
#
|
|
107
|
+
# @example Basic delete
|
|
108
|
+
# db.delete("mykey")
|
|
109
|
+
#
|
|
110
|
+
# @example Delete without waiting for durability
|
|
111
|
+
# db.delete("mykey", await_durable: false)
|
|
112
|
+
#
|
|
113
|
+
def delete(key, await_durable: nil)
|
|
114
|
+
if await_durable.nil?
|
|
115
|
+
_delete(key)
|
|
116
|
+
else
|
|
117
|
+
_delete_with_options(key, { await_durable: await_durable })
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Scan a range of keys.
|
|
122
|
+
#
|
|
123
|
+
# @param start_key [String] The start key (inclusive)
|
|
124
|
+
# @param end_key [String, nil] The end key (exclusive). If nil, scans to end.
|
|
125
|
+
# @param durability_filter [String, nil] Filter by durability level ("remote" or "memory")
|
|
126
|
+
# @param dirty [Boolean, nil] Whether to include uncommitted data
|
|
127
|
+
# @param read_ahead_bytes [Integer, nil] Number of bytes to read ahead
|
|
128
|
+
# @param cache_blocks [Boolean, nil] Whether to cache blocks
|
|
129
|
+
# @param max_fetch_tasks [Integer, nil] Maximum number of fetch tasks
|
|
130
|
+
# @return [Iterator] An iterator over key-value pairs
|
|
131
|
+
#
|
|
132
|
+
# @example Basic scan
|
|
133
|
+
# iter = db.scan("a")
|
|
134
|
+
# while entry = iter.next_entry
|
|
135
|
+
# key, value = entry
|
|
136
|
+
# puts "#{key}: #{value}"
|
|
137
|
+
# end
|
|
138
|
+
#
|
|
139
|
+
# @example Scan with range
|
|
140
|
+
# iter = db.scan("a", "z")
|
|
141
|
+
#
|
|
142
|
+
# @example Scan with block
|
|
143
|
+
# db.scan("user:") do |key, value|
|
|
144
|
+
# puts "#{key}: #{value}"
|
|
145
|
+
# end
|
|
146
|
+
#
|
|
147
|
+
def scan(start_key, end_key = nil, durability_filter: nil, dirty: nil,
|
|
148
|
+
read_ahead_bytes: nil, cache_blocks: nil, max_fetch_tasks: nil, &)
|
|
149
|
+
opts = {}
|
|
150
|
+
opts[:durability_filter] = durability_filter.to_s if durability_filter
|
|
151
|
+
opts[:dirty] = dirty unless dirty.nil?
|
|
152
|
+
opts[:read_ahead_bytes] = read_ahead_bytes if read_ahead_bytes
|
|
153
|
+
opts[:cache_blocks] = cache_blocks unless cache_blocks.nil?
|
|
154
|
+
opts[:max_fetch_tasks] = max_fetch_tasks if max_fetch_tasks
|
|
155
|
+
|
|
156
|
+
iter = if opts.empty?
|
|
157
|
+
_scan(start_key, end_key)
|
|
158
|
+
else
|
|
159
|
+
_scan_with_options(start_key, end_key, opts)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
if block_given?
|
|
163
|
+
iter.each(&)
|
|
164
|
+
else
|
|
165
|
+
iter
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Write a batch of operations atomically.
|
|
170
|
+
#
|
|
171
|
+
# @param batch [WriteBatch] The batch to write
|
|
172
|
+
# @param await_durable [Boolean] Whether to wait for durability (default: true)
|
|
173
|
+
# @return [void]
|
|
174
|
+
#
|
|
175
|
+
# @example Write a batch
|
|
176
|
+
# batch = SlateDb::WriteBatch.new
|
|
177
|
+
# batch.put("key1", "value1")
|
|
178
|
+
# batch.put("key2", "value2")
|
|
179
|
+
# batch.delete("key3")
|
|
180
|
+
# db.write(batch)
|
|
181
|
+
#
|
|
182
|
+
# @example Using batch block helper
|
|
183
|
+
# db.batch do |b|
|
|
184
|
+
# b.put("key1", "value1")
|
|
185
|
+
# b.put("key2", "value2")
|
|
186
|
+
# end
|
|
187
|
+
#
|
|
188
|
+
def write(batch, await_durable: nil)
|
|
189
|
+
if await_durable.nil?
|
|
190
|
+
_write(batch)
|
|
191
|
+
else
|
|
192
|
+
_write_with_options(batch, { await_durable: await_durable })
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Create and write a batch using a block.
|
|
197
|
+
#
|
|
198
|
+
# @param await_durable [Boolean] Whether to wait for durability (default: true)
|
|
199
|
+
# @yield [batch] Yields a WriteBatch to the block
|
|
200
|
+
# @return [void]
|
|
201
|
+
#
|
|
202
|
+
# @example
|
|
203
|
+
# db.batch do |b|
|
|
204
|
+
# b.put("key1", "value1")
|
|
205
|
+
# b.put("key2", "value2")
|
|
206
|
+
# b.delete("old_key")
|
|
207
|
+
# end
|
|
208
|
+
#
|
|
209
|
+
def batch(await_durable: nil)
|
|
210
|
+
b = WriteBatch.new
|
|
211
|
+
yield b
|
|
212
|
+
write(b, await_durable: await_durable)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Begin a new transaction.
|
|
216
|
+
#
|
|
217
|
+
# @param isolation [Symbol, String] Isolation level (:snapshot or :serializable)
|
|
218
|
+
# @yield [txn] If a block is given, yields the transaction and auto-commits/rollbacks
|
|
219
|
+
# @return [Transaction, Object] The transaction (or block result if block given)
|
|
220
|
+
#
|
|
221
|
+
# @example Manual transaction management
|
|
222
|
+
# txn = db.begin_transaction
|
|
223
|
+
# txn.put("key", "value")
|
|
224
|
+
# txn.commit
|
|
225
|
+
#
|
|
226
|
+
# @example Block-based transaction (auto-commit)
|
|
227
|
+
# db.transaction do |txn|
|
|
228
|
+
# txn.put("key", "value")
|
|
229
|
+
# txn.get("other_key")
|
|
230
|
+
# end # automatically committed
|
|
231
|
+
#
|
|
232
|
+
# @example Serializable isolation
|
|
233
|
+
# db.transaction(isolation: :serializable) do |txn|
|
|
234
|
+
# val = txn.get("counter")
|
|
235
|
+
# txn.put("counter", (val.to_i + 1).to_s)
|
|
236
|
+
# end
|
|
237
|
+
#
|
|
238
|
+
def begin_transaction(isolation: nil)
|
|
239
|
+
isolation_str = isolation&.to_s
|
|
240
|
+
_begin_transaction(isolation_str)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Execute a block within a transaction.
|
|
244
|
+
#
|
|
245
|
+
# The transaction is automatically committed if the block succeeds,
|
|
246
|
+
# or rolled back if an exception is raised.
|
|
247
|
+
#
|
|
248
|
+
# @param isolation [Symbol, String] Isolation level (:snapshot or :serializable)
|
|
249
|
+
# @yield [txn] Yields the transaction to the block
|
|
250
|
+
# @return [Object] The result of the block
|
|
251
|
+
#
|
|
252
|
+
# @example
|
|
253
|
+
# result = db.transaction do |txn|
|
|
254
|
+
# old_val = txn.get("counter") || "0"
|
|
255
|
+
# new_val = (old_val.to_i + 1).to_s
|
|
256
|
+
# txn.put("counter", new_val)
|
|
257
|
+
# new_val
|
|
258
|
+
# end
|
|
259
|
+
#
|
|
260
|
+
def transaction(isolation: nil)
|
|
261
|
+
txn = begin_transaction(isolation: isolation)
|
|
262
|
+
begin
|
|
263
|
+
result = yield txn
|
|
264
|
+
txn.commit
|
|
265
|
+
result
|
|
266
|
+
rescue StandardError
|
|
267
|
+
begin
|
|
268
|
+
txn.rollback
|
|
269
|
+
rescue StandardError
|
|
270
|
+
nil
|
|
271
|
+
end
|
|
272
|
+
raise
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# Create a snapshot for consistent reads.
|
|
277
|
+
#
|
|
278
|
+
# @yield [snapshot] If a block is given, yields the snapshot and auto-closes
|
|
279
|
+
# @return [Snapshot, Object] The snapshot (or block result if block given)
|
|
280
|
+
#
|
|
281
|
+
# @example Manual snapshot management
|
|
282
|
+
# snapshot = db.snapshot
|
|
283
|
+
# snapshot.get("key")
|
|
284
|
+
# snapshot.close
|
|
285
|
+
#
|
|
286
|
+
# @example Block-based snapshot (auto-close)
|
|
287
|
+
# db.snapshot do |snap|
|
|
288
|
+
# snap.get("key1")
|
|
289
|
+
# snap.get("key2")
|
|
290
|
+
# end # automatically closed
|
|
291
|
+
#
|
|
292
|
+
def snapshot
|
|
293
|
+
snap = _snapshot
|
|
294
|
+
|
|
295
|
+
if block_given?
|
|
296
|
+
begin
|
|
297
|
+
yield snap
|
|
298
|
+
ensure
|
|
299
|
+
begin
|
|
300
|
+
snap.close
|
|
301
|
+
rescue StandardError
|
|
302
|
+
nil
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
else
|
|
306
|
+
snap
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SlateDb
|
|
4
|
+
class Iterator
|
|
5
|
+
include Enumerable
|
|
6
|
+
|
|
7
|
+
# Iterate over all entries.
|
|
8
|
+
#
|
|
9
|
+
# @yield [key, value] Yields each key-value pair
|
|
10
|
+
# @return [self, Enumerator] Returns self if block given, otherwise an Enumerator
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# iter.each do |key, value|
|
|
14
|
+
# puts "#{key}: #{value}"
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# @example With Enumerable methods
|
|
18
|
+
# iter.map { |k, v| [k.upcase, v] }
|
|
19
|
+
# iter.select { |k, v| k.start_with?("user:") }
|
|
20
|
+
#
|
|
21
|
+
def each
|
|
22
|
+
return to_enum(:each) unless block_given?
|
|
23
|
+
|
|
24
|
+
while (entry = next_entry)
|
|
25
|
+
yield entry
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
self
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SlateDb
|
|
4
|
+
class Reader
|
|
5
|
+
class << self
|
|
6
|
+
# Open a read-only reader at the given path.
|
|
7
|
+
#
|
|
8
|
+
# @param path [String] The path identifier for the database
|
|
9
|
+
# @param url [String, nil] Optional object store URL
|
|
10
|
+
# @param checkpoint_id [String, nil] Optional checkpoint UUID to read at
|
|
11
|
+
# @param manifest_poll_interval [Integer, nil] Poll interval in milliseconds
|
|
12
|
+
# @param checkpoint_lifetime [Integer, nil] Checkpoint lifetime in milliseconds
|
|
13
|
+
# @param max_memtable_bytes [Integer, nil] Maximum memtable size in bytes
|
|
14
|
+
# @yield [reader] If a block is given, yields the reader and ensures it's closed
|
|
15
|
+
# @return [Reader] The opened reader (or block result if block given)
|
|
16
|
+
#
|
|
17
|
+
# @example Open a reader
|
|
18
|
+
# reader = SlateDb::Reader.open("/tmp/mydb")
|
|
19
|
+
# value = reader.get("key")
|
|
20
|
+
# reader.close
|
|
21
|
+
#
|
|
22
|
+
# @example Open with block (auto-close)
|
|
23
|
+
# SlateDb::Reader.open("/tmp/mydb") do |reader|
|
|
24
|
+
# reader.get("key")
|
|
25
|
+
# end # automatically closed
|
|
26
|
+
#
|
|
27
|
+
# @example Open at a specific checkpoint
|
|
28
|
+
# reader = SlateDb::Reader.open("/tmp/mydb", checkpoint_id: "uuid-here")
|
|
29
|
+
#
|
|
30
|
+
def open(path, url: nil, checkpoint_id: nil,
|
|
31
|
+
manifest_poll_interval: nil, checkpoint_lifetime: nil,
|
|
32
|
+
max_memtable_bytes: nil)
|
|
33
|
+
opts = {}
|
|
34
|
+
opts[:manifest_poll_interval] = manifest_poll_interval if manifest_poll_interval
|
|
35
|
+
opts[:checkpoint_lifetime] = checkpoint_lifetime if checkpoint_lifetime
|
|
36
|
+
opts[:max_memtable_bytes] = max_memtable_bytes if max_memtable_bytes
|
|
37
|
+
|
|
38
|
+
reader = _open(path, url, checkpoint_id, opts)
|
|
39
|
+
|
|
40
|
+
if block_given?
|
|
41
|
+
begin
|
|
42
|
+
yield reader
|
|
43
|
+
ensure
|
|
44
|
+
begin
|
|
45
|
+
reader.close
|
|
46
|
+
rescue StandardError
|
|
47
|
+
nil
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
else
|
|
51
|
+
reader
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Get a value by key.
|
|
57
|
+
#
|
|
58
|
+
# @param key [String] The key to look up
|
|
59
|
+
# @param durability_filter [String, nil] Filter by durability level ("remote" or "memory")
|
|
60
|
+
# @param dirty [Boolean, nil] Whether to include uncommitted data
|
|
61
|
+
# @param cache_blocks [Boolean, nil] Whether to cache blocks
|
|
62
|
+
# @return [String, nil] The value, or nil if not found
|
|
63
|
+
#
|
|
64
|
+
def get(key, durability_filter: nil, dirty: nil, cache_blocks: nil)
|
|
65
|
+
opts = {}
|
|
66
|
+
opts[:durability_filter] = durability_filter.to_s if durability_filter
|
|
67
|
+
opts[:dirty] = dirty unless dirty.nil?
|
|
68
|
+
opts[:cache_blocks] = cache_blocks unless cache_blocks.nil?
|
|
69
|
+
|
|
70
|
+
if opts.empty?
|
|
71
|
+
_get(key)
|
|
72
|
+
else
|
|
73
|
+
_get_with_options(key, opts)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Scan a range of keys.
|
|
78
|
+
#
|
|
79
|
+
# @param start_key [String] The start key (inclusive)
|
|
80
|
+
# @param end_key [String, nil] The end key (exclusive)
|
|
81
|
+
# @return [Iterator] An iterator over key-value pairs
|
|
82
|
+
#
|
|
83
|
+
def scan(start_key, end_key = nil, durability_filter: nil, dirty: nil,
|
|
84
|
+
read_ahead_bytes: nil, cache_blocks: nil, max_fetch_tasks: nil, &)
|
|
85
|
+
opts = {}
|
|
86
|
+
opts[:durability_filter] = durability_filter.to_s if durability_filter
|
|
87
|
+
opts[:dirty] = dirty unless dirty.nil?
|
|
88
|
+
opts[:read_ahead_bytes] = read_ahead_bytes if read_ahead_bytes
|
|
89
|
+
opts[:cache_blocks] = cache_blocks unless cache_blocks.nil?
|
|
90
|
+
opts[:max_fetch_tasks] = max_fetch_tasks if max_fetch_tasks
|
|
91
|
+
|
|
92
|
+
iter = if opts.empty?
|
|
93
|
+
_scan(start_key, end_key)
|
|
94
|
+
else
|
|
95
|
+
_scan_with_options(start_key, end_key, opts)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
if block_given?
|
|
99
|
+
iter.each(&)
|
|
100
|
+
else
|
|
101
|
+
iter
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SlateDb
|
|
4
|
+
class Snapshot
|
|
5
|
+
# Get a value by key from the snapshot.
|
|
6
|
+
#
|
|
7
|
+
# @param key [String] The key to look up
|
|
8
|
+
# @param durability_filter [String, nil] Filter by durability level
|
|
9
|
+
# @param dirty [Boolean, nil] Whether to include uncommitted data
|
|
10
|
+
# @param cache_blocks [Boolean, nil] Whether to cache blocks
|
|
11
|
+
# @return [String, nil] The value, or nil if not found
|
|
12
|
+
#
|
|
13
|
+
def get(key, durability_filter: nil, dirty: nil, cache_blocks: nil)
|
|
14
|
+
opts = {}
|
|
15
|
+
opts[:durability_filter] = durability_filter.to_s if durability_filter
|
|
16
|
+
opts[:dirty] = dirty unless dirty.nil?
|
|
17
|
+
opts[:cache_blocks] = cache_blocks unless cache_blocks.nil?
|
|
18
|
+
|
|
19
|
+
if opts.empty?
|
|
20
|
+
_get(key)
|
|
21
|
+
else
|
|
22
|
+
_get_with_options(key, opts)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Scan a range of keys from the snapshot.
|
|
27
|
+
#
|
|
28
|
+
# @param start_key [String] The start key (inclusive)
|
|
29
|
+
# @param end_key [String, nil] The end key (exclusive)
|
|
30
|
+
# @return [Iterator] An iterator over key-value pairs
|
|
31
|
+
#
|
|
32
|
+
def scan(start_key, end_key = nil, durability_filter: nil, dirty: nil,
|
|
33
|
+
read_ahead_bytes: nil, cache_blocks: nil, max_fetch_tasks: nil, &)
|
|
34
|
+
opts = {}
|
|
35
|
+
opts[:durability_filter] = durability_filter.to_s if durability_filter
|
|
36
|
+
opts[:dirty] = dirty unless dirty.nil?
|
|
37
|
+
opts[:read_ahead_bytes] = read_ahead_bytes if read_ahead_bytes
|
|
38
|
+
opts[:cache_blocks] = cache_blocks unless cache_blocks.nil?
|
|
39
|
+
opts[:max_fetch_tasks] = max_fetch_tasks if max_fetch_tasks
|
|
40
|
+
|
|
41
|
+
iter = if opts.empty?
|
|
42
|
+
_scan(start_key, end_key)
|
|
43
|
+
else
|
|
44
|
+
_scan_with_options(start_key, end_key, opts)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
if block_given?
|
|
48
|
+
iter.each(&)
|
|
49
|
+
else
|
|
50
|
+
iter
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SlateDb
|
|
4
|
+
class Transaction
|
|
5
|
+
# Get a value by key within the transaction.
|
|
6
|
+
#
|
|
7
|
+
# @param key [String] The key to look up
|
|
8
|
+
# @param durability_filter [String, nil] Filter by durability level
|
|
9
|
+
# @param dirty [Boolean, nil] Whether to include uncommitted data
|
|
10
|
+
# @param cache_blocks [Boolean, nil] Whether to cache blocks
|
|
11
|
+
# @return [String, nil] The value, or nil if not found
|
|
12
|
+
#
|
|
13
|
+
def get(key, durability_filter: nil, dirty: nil, cache_blocks: nil)
|
|
14
|
+
opts = {}
|
|
15
|
+
opts[:durability_filter] = durability_filter.to_s if durability_filter
|
|
16
|
+
opts[:dirty] = dirty unless dirty.nil?
|
|
17
|
+
opts[:cache_blocks] = cache_blocks unless cache_blocks.nil?
|
|
18
|
+
|
|
19
|
+
if opts.empty?
|
|
20
|
+
_get(key)
|
|
21
|
+
else
|
|
22
|
+
_get_with_options(key, opts)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Store a key-value pair within the transaction.
|
|
27
|
+
#
|
|
28
|
+
# @param key [String] The key to store
|
|
29
|
+
# @param value [String] The value to store
|
|
30
|
+
# @param ttl [Integer, nil] Time-to-live in milliseconds
|
|
31
|
+
# @return [void]
|
|
32
|
+
#
|
|
33
|
+
def put(key, value, ttl: nil)
|
|
34
|
+
if ttl
|
|
35
|
+
_put_with_options(key, value, { ttl: ttl })
|
|
36
|
+
else
|
|
37
|
+
_put(key, value)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Delete a key within the transaction.
|
|
42
|
+
#
|
|
43
|
+
# @param key [String] The key to delete
|
|
44
|
+
# @return [void]
|
|
45
|
+
#
|
|
46
|
+
def delete(key)
|
|
47
|
+
_delete(key)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Scan a range of keys within the transaction.
|
|
51
|
+
#
|
|
52
|
+
# @param start_key [String] The start key (inclusive)
|
|
53
|
+
# @param end_key [String, nil] The end key (exclusive)
|
|
54
|
+
# @return [Iterator] An iterator over key-value pairs
|
|
55
|
+
#
|
|
56
|
+
def scan(start_key, end_key = nil, durability_filter: nil, dirty: nil,
|
|
57
|
+
read_ahead_bytes: nil, cache_blocks: nil, max_fetch_tasks: nil, &)
|
|
58
|
+
opts = {}
|
|
59
|
+
opts[:durability_filter] = durability_filter.to_s if durability_filter
|
|
60
|
+
opts[:dirty] = dirty unless dirty.nil?
|
|
61
|
+
opts[:read_ahead_bytes] = read_ahead_bytes if read_ahead_bytes
|
|
62
|
+
opts[:cache_blocks] = cache_blocks unless cache_blocks.nil?
|
|
63
|
+
opts[:max_fetch_tasks] = max_fetch_tasks if max_fetch_tasks
|
|
64
|
+
|
|
65
|
+
iter = if opts.empty?
|
|
66
|
+
_scan(start_key, end_key)
|
|
67
|
+
else
|
|
68
|
+
_scan_with_options(start_key, end_key, opts)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
if block_given?
|
|
72
|
+
iter.each(&)
|
|
73
|
+
else
|
|
74
|
+
iter
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SlateDb
|
|
4
|
+
class WriteBatch
|
|
5
|
+
# Add a put operation to the batch.
|
|
6
|
+
#
|
|
7
|
+
# @param key [String] The key to store
|
|
8
|
+
# @param value [String] The value to store
|
|
9
|
+
# @param ttl [Integer, nil] Time-to-live in milliseconds
|
|
10
|
+
# @return [self] Returns self for method chaining
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# batch.put("key", "value")
|
|
14
|
+
# batch.put("key2", "value2", ttl: 60_000)
|
|
15
|
+
#
|
|
16
|
+
def put(key, value, ttl: nil)
|
|
17
|
+
if ttl
|
|
18
|
+
_put_with_options(key, value, { ttl: ttl })
|
|
19
|
+
else
|
|
20
|
+
_put(key, value)
|
|
21
|
+
end
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Add a delete operation to the batch.
|
|
26
|
+
#
|
|
27
|
+
# @param key [String] The key to delete
|
|
28
|
+
# @return [self] Returns self for method chaining
|
|
29
|
+
#
|
|
30
|
+
# @example
|
|
31
|
+
# batch.delete("key")
|
|
32
|
+
#
|
|
33
|
+
def delete(key)
|
|
34
|
+
_delete(key)
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/slatedb.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "slatedb/version"
|
|
4
|
+
|
|
5
|
+
# Load the native extension
|
|
6
|
+
begin
|
|
7
|
+
RUBY_VERSION =~ /(\d+\.\d+)/
|
|
8
|
+
require "slatedb/#{Regexp.last_match(1)}/slatedb"
|
|
9
|
+
rescue LoadError
|
|
10
|
+
require "slatedb/slatedb"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Load Ruby class extensions
|
|
14
|
+
require_relative "slatedb/database"
|
|
15
|
+
require_relative "slatedb/iterator"
|
|
16
|
+
require_relative "slatedb/write_batch"
|
|
17
|
+
require_relative "slatedb/transaction"
|
|
18
|
+
require_relative "slatedb/snapshot"
|
|
19
|
+
require_relative "slatedb/reader"
|
|
20
|
+
require_relative "slatedb/admin"
|