0
# Transaction Management
1
2
Transaction lifecycle management including creation, execution, error handling, and retry logic with optimistic concurrency control. FoundationDB transactions provide ACID guarantees across the distributed system.
3
4
## Capabilities
5
6
### Transaction Lifecycle
7
8
Basic transaction operations for managing the transaction state and completing operations.
9
10
```c { .api }
11
/**
12
* Commit the transaction and make changes durable
13
* @param tr Transaction handle
14
* @return Future that completes when commit finishes
15
*/
16
FDBFuture* fdb_transaction_commit(FDBTransaction* tr);
17
18
/**
19
* Cancel the transaction, aborting all changes
20
* @param tr Transaction handle
21
*/
22
void fdb_transaction_cancel(FDBTransaction* tr);
23
24
/**
25
* Reset transaction to initial state, clearing all changes
26
* @param tr Transaction handle
27
*/
28
void fdb_transaction_reset(FDBTransaction* tr);
29
30
/**
31
* Get the committed version after successful commit
32
* @param tr Transaction handle
33
* @param out_version Pointer to store committed version
34
* @return Error code (0 for success)
35
*/
36
fdb_error_t fdb_transaction_get_committed_version(FDBTransaction* tr, int64_t* out_version);
37
```
38
39
```python { .api }
40
class Transaction:
41
def commit(self) -> Future:
42
"""
43
Commit the transaction
44
45
Returns:
46
Future that completes when commit finishes
47
"""
48
49
def cancel(self) -> None:
50
"""Cancel the transaction, aborting all changes"""
51
52
def reset(self) -> None:
53
"""Reset transaction to initial state"""
54
55
def get_committed_version(self) -> int:
56
"""
57
Get committed version after successful commit
58
59
Returns:
60
Committed version number
61
"""
62
```
63
64
```java { .api }
65
// Java API
66
public interface Transaction {
67
public CompletableFuture<Void> commit():
68
/**
69
* Commit the transaction asynchronously
70
* @return CompletableFuture that completes when commit finishes
71
*/
72
73
public void cancel():
74
/**
75
* Cancel the transaction
76
*/
77
78
public void reset():
79
/**
80
* Reset transaction to initial state
81
*/
82
83
public long getCommittedVersion():
84
/**
85
* Get committed version after successful commit
86
* @return Committed version number
87
*/
88
}
89
```
90
91
```go { .api }
92
// Go API
93
type Transaction interface {
94
Commit() FutureNil:
95
/**
96
* Commit the transaction
97
* @return Future that completes when commit finishes
98
*/
99
100
Cancel():
101
/**
102
* Cancel the transaction
103
*/
104
105
Reset():
106
/**
107
* Reset transaction to initial state
108
*/
109
110
GetCommittedVersion() (int64, error):
111
/**
112
* Get committed version after successful commit
113
* @return Committed version and error
114
*/
115
}
116
```
117
118
### Error Handling and Retry Logic
119
120
Handle transaction errors and implement retry logic for transient failures.
121
122
```c { .api }
123
/**
124
* Handle transaction errors and determine if retry is possible
125
* @param tr Transaction handle
126
* @param error Error code from previous operation
127
* @return Future that completes when error handling is done
128
*/
129
FDBFuture* fdb_transaction_on_error(FDBTransaction* tr, fdb_error_t error);
130
```
131
132
```python { .api }
133
class Transaction:
134
def on_error(self, error: FDBError) -> Future:
135
"""
136
Handle transaction error and prepare for retry if possible
137
138
Args:
139
error: FDBError from previous operation
140
141
Returns:
142
Future that completes when retry is ready or raises if not retryable
143
"""
144
145
def transactional(func: Callable) -> Callable:
146
"""
147
Decorator that automatically handles transaction retry logic
148
149
Args:
150
func: Function that takes Transaction as first argument
151
152
Returns:
153
Wrapped function that handles retries automatically
154
"""
155
```
156
157
```java { .api }
158
// Java API
159
public interface Transaction {
160
public CompletableFuture<Void> onError(FDBException error):
161
/**
162
* Handle transaction error and prepare for retry
163
* @param error Exception from previous operation
164
* @return CompletableFuture for retry preparation
165
*/
166
}
167
168
public interface Database {
169
public <T> T run(Function<Transaction, T> retryable):
170
/**
171
* Execute function with automatic retry logic
172
* @param retryable Function to execute in transaction
173
* @return Result of function execution
174
*/
175
176
public <T> CompletableFuture<T> runAsync(Function<Transaction, CompletableFuture<T>> retryable):
177
/**
178
* Execute async function with automatic retry logic
179
* @param retryable Async function to execute in transaction
180
* @return CompletableFuture with result
181
*/
182
}
183
```
184
185
```go { .api }
186
// Go API
187
type Transaction interface {
188
OnError(err Error) FutureNil:
189
/**
190
* Handle transaction error and prepare for retry
191
* @param err Error from previous operation
192
* @return Future for retry preparation
193
*/
194
}
195
196
type Transactor interface {
197
Transact(func(Transaction) (interface{}, error)) (interface{}, error):
198
/**
199
* Execute function with automatic retry logic
200
* @param fn Function to execute in transaction context
201
* @return Result and error
202
*/
203
}
204
```
205
206
### Version Management
207
208
Manage read and write versions for controlling transaction consistency and timestamps.
209
210
```c { .api }
211
/**
212
* Set the read version for the transaction
213
* @param tr Transaction handle
214
* @param version Version to use for reads
215
*/
216
void fdb_transaction_set_read_version(FDBTransaction* tr, int64_t version);
217
218
/**
219
* Get the read version that will be used for this transaction
220
* @param tr Transaction handle
221
* @return Future containing the read version
222
*/
223
FDBFuture* fdb_transaction_get_read_version(FDBTransaction* tr);
224
225
/**
226
* Get a versionstamp for this transaction
227
* @param tr Transaction handle
228
* @return Future containing the versionstamp
229
*/
230
FDBFuture* fdb_transaction_get_versionstamp(FDBTransaction* tr);
231
```
232
233
```python { .api }
234
class Transaction:
235
def set_read_version(self, version: int) -> None:
236
"""
237
Set the read version for this transaction
238
239
Args:
240
version: Version number to use for reads
241
"""
242
243
def get_read_version(self) -> Future:
244
"""
245
Get the read version for this transaction
246
247
Returns:
248
Future containing read version number
249
"""
250
251
def get_versionstamp(self) -> Future:
252
"""
253
Get a versionstamp for this transaction
254
255
Returns:
256
Future containing 10-byte versionstamp
257
"""
258
```
259
260
```java { .api }
261
// Java API
262
public interface Transaction {
263
public void setReadVersion(long version):
264
/**
265
* Set the read version for this transaction
266
* @param version Version number to use for reads
267
*/
268
269
public CompletableFuture<Long> getReadVersion():
270
/**
271
* Get the read version for this transaction
272
* @return CompletableFuture with read version
273
*/
274
275
public CompletableFuture<byte[]> getVersionstamp():
276
/**
277
* Get a versionstamp for this transaction
278
* @return CompletableFuture with 10-byte versionstamp
279
*/
280
}
281
```
282
283
```go { .api }
284
// Go API
285
type Transaction interface {
286
SetReadVersion(version int64):
287
/**
288
* Set the read version for this transaction
289
* @param version Version number to use for reads
290
*/
291
292
GetReadVersion() FutureInt64:
293
/**
294
* Get the read version for this transaction
295
* @return Future with read version
296
*/
297
298
GetVersionstamp() FutureKey:
299
/**
300
* Get a versionstamp for this transaction
301
* @return Future with 10-byte versionstamp
302
*/
303
}
304
```
305
306
### Conflict Range Management
307
308
Manage read and write conflict ranges to control transaction conflict detection.
309
310
```c { .api }
311
/**
312
* Add a conflict range to the transaction
313
* @param tr Transaction handle
314
* @param begin_key_name Start of key range
315
* @param begin_key_name_length Length of start key
316
* @param end_key_name End of key range (exclusive)
317
* @param end_key_name_length Length of end key
318
* @param type Type of conflict range (read or write)
319
* @return Error code (0 for success)
320
*/
321
fdb_error_t fdb_transaction_add_conflict_range(FDBTransaction* tr,
322
uint8_t const* begin_key_name, int begin_key_name_length,
323
uint8_t const* end_key_name, int end_key_name_length,
324
FDBConflictRangeType type);
325
```
326
327
```python { .api }
328
class Transaction:
329
def add_read_conflict_range(self, begin: bytes, end: bytes) -> None:
330
"""
331
Add a read conflict range
332
333
Args:
334
begin: Start of key range (inclusive)
335
end: End of key range (exclusive)
336
"""
337
338
def add_write_conflict_range(self, begin: bytes, end: bytes) -> None:
339
"""
340
Add a write conflict range
341
342
Args:
343
begin: Start of key range (inclusive)
344
end: End of key range (exclusive)
345
"""
346
347
def add_read_conflict_key(self, key: bytes) -> None:
348
"""
349
Add a single key read conflict range
350
351
Args:
352
key: Key to add to read conflict set
353
"""
354
355
def add_write_conflict_key(self, key: bytes) -> None:
356
"""
357
Add a single key write conflict range
358
359
Args:
360
key: Key to add to write conflict set
361
"""
362
```
363
364
```java { .api }
365
// Java API
366
public interface Transaction {
367
public void addReadConflictRange(byte[] begin, byte[] end):
368
/**
369
* Add a read conflict range
370
* @param begin Start of key range (inclusive)
371
* @param end End of key range (exclusive)
372
*/
373
374
public void addWriteConflictRange(byte[] begin, byte[] end):
375
/**
376
* Add a write conflict range
377
* @param begin Start of key range (inclusive)
378
* @param end End of key range (exclusive)
379
*/
380
381
public void addReadConflictKey(byte[] key):
382
/**
383
* Add a single key read conflict range
384
* @param key Key to add to read conflict set
385
*/
386
387
public void addWriteConflictKey(byte[] key):
388
/**
389
* Add a single key write conflict range
390
* @param key Key to add to write conflict set
391
*/
392
}
393
```
394
395
```go { .api }
396
// Go API
397
type Transaction interface {
398
AddReadConflictRange(begin, end Key) error:
399
/**
400
* Add a read conflict range
401
* @param begin Start of key range
402
* @param end End of key range
403
* @return Error if operation fails
404
*/
405
406
AddWriteConflictRange(begin, end Key) error:
407
/**
408
* Add a write conflict range
409
* @param begin Start of key range
410
* @param end End of key range
411
* @return Error if operation fails
412
*/
413
414
AddReadConflictKey(key Key) error:
415
/**
416
* Add a single key read conflict range
417
* @param key Key to add to read conflict set
418
* @return Error if operation fails
419
*/
420
421
AddWriteConflictKey(key Key) error:
422
/**
423
* Add a single key write conflict range
424
* @param key Key to add to write conflict set
425
* @return Error if operation fails
426
*/
427
}
428
```
429
430
### Transaction Size and Performance
431
432
Monitor and manage transaction size for optimal performance.
433
434
```c { .api }
435
/**
436
* Get approximate size of the transaction in bytes
437
* @param tr Transaction handle
438
* @return Future containing approximate transaction size
439
*/
440
FDBFuture* fdb_transaction_get_approximate_size(FDBTransaction* tr);
441
```
442
443
```python { .api }
444
class Transaction:
445
def get_approximate_size(self) -> Future:
446
"""
447
Get approximate size of the transaction
448
449
Returns:
450
Future containing transaction size in bytes
451
"""
452
```
453
454
```java { .api }
455
// Java API
456
public interface Transaction {
457
public CompletableFuture<Long> getApproximateSize():
458
/**
459
* Get approximate size of the transaction
460
* @return CompletableFuture with transaction size in bytes
461
*/
462
}
463
```
464
465
```go { .api }
466
// Go API
467
type Transaction interface {
468
GetApproximateSize() FutureInt64:
469
/**
470
* Get approximate size of the transaction
471
* @return Future with transaction size in bytes
472
*/
473
}
474
```
475
476
**Usage Examples:**
477
478
**Manual Transaction with Retry Logic (C):**
479
```c
480
void execute_with_retry(FDBDatabase* db) {
481
FDBTransaction* tr;
482
fdb_database_create_transaction(db, &tr);
483
484
while (1) {
485
// Set a value
486
fdb_transaction_set(tr, (uint8_t*)"key", 3, (uint8_t*)"value", 5);
487
488
// Try to commit
489
FDBFuture* commit_future = fdb_transaction_commit(tr);
490
fdb_error_t commit_err = fdb_future_block_until_ready(commit_future);
491
fdb_future_destroy(commit_future);
492
493
if (commit_err == 0) {
494
// Success!
495
break;
496
} else {
497
// Handle error and retry if possible
498
FDBFuture* error_future = fdb_transaction_on_error(tr, commit_err);
499
fdb_error_t retry_err = fdb_future_block_until_ready(error_future);
500
fdb_future_destroy(error_future);
501
502
if (retry_err != 0) {
503
// Not retryable, give up
504
break;
505
}
506
// Continue loop to retry
507
}
508
}
509
510
fdb_transaction_destroy(tr);
511
}
512
```
513
514
**Automatic Retry with Decorator (Python):**
515
```python
516
import fdb
517
518
fdb.api_version(630)
519
db = fdb.open()
520
521
@fdb.transactional
522
def update_counter(tr, key):
523
# Get current value
524
current = tr.get(key).wait()
525
count = int(current) if current else 0
526
527
# Increment and store
528
tr.set(key, str(count + 1).encode())
529
return count + 1
530
531
# This will automatically retry on conflicts
532
new_count = update_counter(db, b"counter")
533
print(f"New count: {new_count}")
534
```
535
536
**Database.run() with Automatic Retry (Java):**
537
```java
538
import com.apple.foundationdb.*;
539
540
FDB fdb = FDB.selectAPIVersion(630);
541
542
try (Database db = fdb.open()) {
543
// Automatic retry logic
544
Integer result = db.run(tr -> {
545
// Get current value
546
byte[] currentBytes = tr.get(Tuple.from("counter").pack()).join();
547
int current = currentBytes != null ? Integer.parseInt(new String(currentBytes)) : 0;
548
549
// Increment and store
550
int newValue = current + 1;
551
tr.set(Tuple.from("counter").pack(), String.valueOf(newValue).getBytes());
552
553
return newValue;
554
});
555
556
System.out.println("New count: " + result);
557
}
558
```
559
560
**Transactor Interface with Retry (Go):**
561
```go
562
package main
563
564
import (
565
"fmt"
566
"strconv"
567
"github.com/apple/foundationdb/bindings/go/src/fdb"
568
"github.com/apple/foundationdb/bindings/go/src/fdb/tuple"
569
)
570
571
func main() {
572
fdb.MustAPIVersion(630)
573
db := fdb.MustOpenDefault()
574
575
// Automatic retry logic
576
result, err := db.Transact(func(tr fdb.Transaction) (interface{}, error) {
577
// Get current value
578
key := tuple.Tuple{"counter"}.Pack()
579
currentBytes := tr.Get(fdb.Key(key)).MustGet()
580
581
current := 0
582
if currentBytes != nil {
583
current, _ = strconv.Atoi(string(currentBytes))
584
}
585
586
// Increment and store
587
newValue := current + 1
588
tr.Set(fdb.Key(key), []byte(strconv.Itoa(newValue)))
589
590
return newValue, nil
591
})
592
593
if err != nil {
594
panic(err)
595
}
596
597
fmt.Printf("New count: %d\n", result.(int))
598
}
599
```