Golang Versionstamp usage

(Ryan Worl) #1

I’m attempting to create a Versionstamp key using the Golang client library.

\x00\x00\x00@\xb9\x1aK\x1d\x00\x00\x00\x00\x00\x00\x00 is a key created from the following code:

_, err := db.Transact(func(tr fdb.Transaction) (interface{}, error) {
	keyBytes := append([]byte("stream/"), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
	baseKey := fdb.Key(keyBytes)
	tr.SetVersionstampedKey(baseKey, []byte("world"))
	return nil, nil

I understand the advantages of using the tuple layer in terms of problems with the byte ordering of delimiters, but the docs say I can’t use a Versionstamp in the Golang tuple layer at this time.

How do I make the “stream/” portion appear in the beginning of the key?

I accomplished this in Python in a quite straightforward way using the tuple layer and I can’t find any equivalent in Golang.

Transaction.Watch Examples?
(Christophe Chevalier) #2

You need to append 2 bytes at the end of the key that contain the offset of the start of the versionstamp (in little endian). So since “stream/” is 7 bytes, you need to append 07 00 at the end, and pass that to SetVersionstampedKey() : -> 'stream/'.<00000000000000000000>.<0700>

Once committed, this should become something like 'stream/'.<XXXXXXXXXXXXyyyy> (with XXXX the transaction version, and yyyy probably 0000 in my testing).

I believe the Tuple Layers in Java and Python have a dedicated serialization method that will track the position of the stamp, and automatically append that offset for you. (this probably has not been implemented in the go layer yet?)

(Alec Grieser) #3

Yep, that’s right. The go bindings support versionstamps, but the tuple layer (in go) does not, and that’s just because it hasn’t been implemented (there isn’t some deep philosophical reason why it couldn’t be or shouldn’t be). And yeah, if it only had to read versionstamps, that would be easy (just add a new type to the list and serialize it correctly), but if you want it to correctly add the position for you, that’s the hard part that the Python and Java tuples do for you.

(seddonm1) #4

I hope someone is able to implement the correct handling of these versionstamps golang. Sounds very useful but a bit out of my comfort zone.

(seddonm1) #5

I have been playing with the SetVersionstampedKey api using golang using the code above appending the additional 2 byte offset to be able to split the versionstamp from the prefix which works fine for a single SetVersionstampedKey per transaction (as expected) but I have not seen how to perform multiple SetVersionstampedKey operations in a single transaction with correct ordering. I am seeking a way to ensure ordering of events without using timestamps (due to their inherent problems) by letting fdb set the key.

I thought that I could just append a transaction set index number so that each insert would look like 'stream/'.<versionstamp>.<i> but the trailing bytes get dropped by the set.

keyBytes := append([]byte("stream/"))
keyBytes = append(keyBytes, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0)
binary.BigEndian.PutUint16(b, i)
keyBytes = append(keyBytes, b[0], b[1])

Should I just be using the SetVersionstampedKey api for single inserts per transaction or is there another way to achieve this desired behaviour?

(A.J. Beamon) #6

If I understand the code snippet correctly, I think the problem here is the location of the versionstamp offset. The offset needs to be the last two bytes of the entire key rather than being placed at the end of the 10-byte placeholder (and note, this is likely going to change to a 4 byte offset in an upcoming release). So if you swap the locations of i and the offset, I think you’ll get the desired behavior.

And to answer the general question, it should be possible to set multiple keys with versionstamps in the same transaction, and if you do each key should have the same versionstamp inserted into it.

(seddonm1) #7

Wow. Of course. I had been looking at the problem for too long (with interruptions) and totally missed the obvious. Yes this works:

'stream/'.<versionstamp 10 bytes of 0>.<transaction insert seq offset 2 bytes>.<'stream/' offset two bytes little endian = 7, 0>