Hello everyone. I’m working on a Swift FoundationDB client. From day one I used FDB_STREAMING_MODE_WANT_ALL
as default streaming mode in range get function (link) as I’m feeling it suits best for most of my usecases. In rare cases when I used different modes (I think it only was FDB_STREAMING_MODE_ITERATOR
), I haven’t noticed anything suspicious.
However, I recently started working on a stable LTS version of my client and wanted to add a handy sugar iterator(-ish) functionality to the client (link) which would manage iteration
counter for user and return nil
when there are no more records in DB (though it’s not compatible with Swift builtin IteratorProtocol
as my implementation can throw error).
When I was covering this new functionality with tests (link), I noticed quite strange behaviour: iterator mode wasn’t working as expected. Say I insert 10 rows to the FDB (value is just one byte, incrementing from 1 to 10), and then I’d like to get this range as an iterator.
Firstly, I noticed that iterator mode ignores limit
argument (I wanted to iterate 3 records per iteration), though it wasn’t a big surprise as I eventually found out in FDB sources that FDB returns increasing portions of rows in this mode. No problems here really, however, it would be nice if it would actually obey limit
when I do want it.
But the funniest thing is it would return only first 4 records every time, no matter the iteration
counter. I even introduced ultra-verbose printing of all C function invocations, and there’s no mistake (or at least it seems so to me):
// First invocation here is WANT_ALL to return all rows
// from this range and confirm that there are actually 10 rows
[FDB] [Transaction] Calling C function fdb_transaction_get_range(
FDBTransaction* tr: 0x0000000100c19660
uint8_t const* begin_key_name: [..., 114, 0, 0]
int begin_key_name_length: 42
fdb_bool_t begin_or_equal: 0
int begin_offset: 1
uint8_t const* end_key_name: [..., 114, 0, 255]
int end_key_name_length: 42
fdb_bool_t end_or_equal: 0
int end_offset: 1
int limit: 0
int target_bytes: 0
FDBStreamingMode mode: FDBStreamingMode(rawValue: -2)
int iteration: 1
fdb_bool_t snapshot: 0
fdb_bool_t reverse: 0
)
["all": [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]]
// And after that I call `next()` four times,
// and you can see that iteration is incremented every time,
// but only first four rows are returned every time
[FDB] [Transaction] Calling C function fdb_transaction_get_range(
FDBTransaction* tr: 0x0000000100c217d0
uint8_t const* begin_key_name: [..., 114, 0, 0]
int begin_key_name_length: 42
fdb_bool_t begin_or_equal: 0
int begin_offset: 1
uint8_t const* end_key_name: [..., 114, 0, 255]
int end_key_name_length: 42
fdb_bool_t end_or_equal: 0
int end_offset: 1
int limit: 0
int target_bytes: 0
FDBStreamingMode mode: FDBStreamingMode(rawValue: -1)
int iteration: 1
fdb_bool_t snapshot: 0
fdb_bool_t reverse: 0
)
[[1], [2], [3], [4]]
[FDB] [Transaction] Calling C function fdb_transaction_get_range(
FDBTransaction* tr: 0x0000000100c217d0
uint8_t const* begin_key_name: [..., 114, 0, 0]
int begin_key_name_length: 42
fdb_bool_t begin_or_equal: 0
int begin_offset: 1
uint8_t const* end_key_name: [..., 114, 0, 255]
int end_key_name_length: 42
fdb_bool_t end_or_equal: 0
int end_offset: 1
int limit: 0
int target_bytes: 0
FDBStreamingMode mode: FDBStreamingMode(rawValue: -1)
int iteration: 2
fdb_bool_t snapshot: 0
fdb_bool_t reverse: 0
)
[[1], [2], [3], [4]]
[FDB] [Transaction] Calling C function fdb_transaction_get_range(
FDBTransaction* tr: 0x0000000100c217d0
uint8_t const* begin_key_name: [..., 114, 0, 0]
int begin_key_name_length: 42
fdb_bool_t begin_or_equal: 0
int begin_offset: 1
uint8_t const* end_key_name: [..., 114, 0, 255]
int end_key_name_length: 42
fdb_bool_t end_or_equal: 0
int end_offset: 1
int limit: 0
int target_bytes: 0
FDBStreamingMode mode: FDBStreamingMode(rawValue: -1)
int iteration: 3
fdb_bool_t snapshot: 0
fdb_bool_t reverse: 0
)
[[1], [2], [3], [4]]
[FDB] [Transaction] Calling C function fdb_transaction_get_range(
FDBTransaction* tr: 0x0000000100c217d0
uint8_t const* begin_key_name: [..., 114, 0, 0]
int begin_key_name_length: 42
fdb_bool_t begin_or_equal: 0
int begin_offset: 1
uint8_t const* end_key_name: [..., 114, 0, 255]
int end_key_name_length: 42
fdb_bool_t end_or_equal: 0
int end_offset: 1
int limit: 0
int target_bytes: 0
FDBStreamingMode mode: FDBStreamingMode(rawValue: -1)
int iteration: 4
fdb_bool_t snapshot: 0
fdb_bool_t reverse: 0
)
[[1], [2], [3], [4]]
I’m genuinely confused, please help. Either I’m missing something (most probably) or there is a bug in FDB.
I’m using FoundationDB v6.0.18 with 600 header API version.
Thanks in advance!