@@ -36,8 +36,6 @@ namespace FoundationDB.Client.Tests
3636 using System . Text ;
3737 using System . Threading ;
3838 using System . Threading . Tasks ;
39- using Doxense . Collections . Tuples ;
40- using Doxense . Memory ;
4139
4240 [ TestFixture ]
4341 public class TransactionFacts : FdbTest
@@ -1991,6 +1989,77 @@ public async Task Test_Simple_Read_Transaction()
19911989 }
19921990 }
19931991
1992+ [ Test ]
1993+ public async Task Test_VersionStamps_Share_The_Same_Token_Per_Transaction_Attempt ( )
1994+ {
1995+ // Veryify that we can set versionstamped keys inside a transaction
1996+
1997+ using ( var db = await OpenTestDatabaseAsync ( ) )
1998+ {
1999+ using ( var tr = db . BeginTransaction ( this . Cancellation ) )
2000+ {
2001+ // should return a 80-bit incomplete stamp, using a random token
2002+ var x = tr . CreateVersionStamp ( ) ;
2003+ Log ( $ "> x : { x } with token '{ x . ToSlice ( ) : X} '") ;
2004+ Assert . That ( x . IsIncomplete , Is . True , "Placeholder token should be incomplete" ) ;
2005+ Assert . That ( x . HasUserVersion , Is . False ) ;
2006+ Assert . That ( x . UserVersion , Is . Zero ) ;
2007+ Assert . That ( x . TransactionVersion >> 56 , Is . EqualTo ( 0xFF ) , "Highest 8 bit of Transaction Version should be set to 1" ) ;
2008+ Assert . That ( x . TransactionOrder >> 12 , Is . EqualTo ( 0xF ) , "Hight 4 bits of Transaction Order should be set to 1" ) ;
2009+
2010+ // should return a 96-bit incomplete stamp, using a the same random token and user version 0
2011+ var x0 = tr . CreateVersionStamp ( 0 ) ;
2012+ Log ( $ "> x0 : { x0 . ToSlice ( ) : X} => { x0 } ") ;
2013+ Assert . That ( x0 . IsIncomplete , Is . True , "Placeholder token should be incomplete" ) ;
2014+ Assert . That ( x0 . TransactionVersion , Is . EqualTo ( x . TransactionVersion ) , "All generated stamps by one transaction should share the random token value " ) ;
2015+ Assert . That ( x0 . TransactionOrder , Is . EqualTo ( x . TransactionOrder ) , "All generated stamps by one transaction should share the random token value " ) ;
2016+ Assert . That ( x0 . HasUserVersion , Is . True ) ;
2017+ Assert . That ( x0 . UserVersion , Is . EqualTo ( 0 ) ) ;
2018+
2019+ // should return a 96-bit incomplete stamp, using a the same random token and user version 1
2020+ var x1 = tr . CreateVersionStamp ( 1 ) ;
2021+ Log ( $ "> x1 : { x1 . ToSlice ( ) : X} => { x1 } ") ;
2022+ Assert . That ( x1 . IsIncomplete , Is . True , "Placeholder token should be incomplete" ) ;
2023+ Assert . That ( x1 . TransactionVersion , Is . EqualTo ( x . TransactionVersion ) , "All generated stamps by one transaction should share the random token value " ) ;
2024+ Assert . That ( x1 . TransactionOrder , Is . EqualTo ( x . TransactionOrder ) , "All generated stamps by one transaction should share the random token value " ) ;
2025+ Assert . That ( x1 . HasUserVersion , Is . True ) ;
2026+ Assert . That ( x1 . UserVersion , Is . EqualTo ( 1 ) ) ;
2027+
2028+ // should return a 96-bit incomplete stamp, using a the same random token and user version 42
2029+ var x42 = tr . CreateVersionStamp ( 42 ) ;
2030+ Log ( $ "> x42: { x42 . ToSlice ( ) : X} => { x42 } ") ;
2031+ Assert . That ( x42 . IsIncomplete , Is . True , "Placeholder token should be incomplete" ) ;
2032+ Assert . That ( x42 . TransactionVersion , Is . EqualTo ( x . TransactionVersion ) , "All generated stamps by one transaction should share the random token value " ) ;
2033+ Assert . That ( x42 . TransactionOrder , Is . EqualTo ( x . TransactionOrder ) , "All generated stamps by one transaction should share the random token value " ) ;
2034+ Assert . That ( x42 . HasUserVersion , Is . True ) ;
2035+ Assert . That ( x42 . UserVersion , Is . EqualTo ( 42 ) ) ;
2036+
2037+ // Reset the transaction
2038+ // => stamps should use a new value
2039+ Log ( "Reset!" ) ;
2040+ tr . Reset ( ) ;
2041+
2042+ var y = tr . CreateVersionStamp ( ) ;
2043+ Log ( $ "> y : { y . ToSlice ( ) : X} => { y } '") ;
2044+ Assert . That ( y , Is . Not . EqualTo ( x ) , "VersionStamps should change when a transaction is reset" ) ;
2045+
2046+ Assert . That ( y . IsIncomplete , Is . True , "Placeholder token should be incomplete" ) ;
2047+ Assert . That ( y . HasUserVersion , Is . False ) ;
2048+ Assert . That ( y . UserVersion , Is . Zero ) ;
2049+ Assert . That ( y . TransactionVersion >> 56 , Is . EqualTo ( 0xFF ) , "Highest 8 bit of Transaction Version should be set to 1" ) ;
2050+ Assert . That ( y . TransactionOrder >> 12 , Is . EqualTo ( 0xF ) , "Hight 4 bits of Transaction Order should be set to 1" ) ;
2051+
2052+ var y42 = tr . CreateVersionStamp ( 42 ) ;
2053+ Log ( $ "> y42: { y42 . ToSlice ( ) : X} => { y42 } ") ;
2054+ Assert . That ( y42 . IsIncomplete , Is . True , "Placeholder token should be incomplete" ) ;
2055+ Assert . That ( y42 . TransactionVersion , Is . EqualTo ( y . TransactionVersion ) , "All generated stamps by one transaction should share the random token value " ) ;
2056+ Assert . That ( y42 . TransactionOrder , Is . EqualTo ( y . TransactionOrder ) , "All generated stamps by one transaction should share the random token value " ) ;
2057+ Assert . That ( y42 . HasUserVersion , Is . True ) ;
2058+ Assert . That ( y42 . UserVersion , Is . EqualTo ( 42 ) ) ;
2059+ }
2060+ }
2061+ }
2062+
19942063 [ Test ]
19952064 public async Task Test_VersionStamp_Operations ( )
19962065 {
@@ -2007,60 +2076,23 @@ public async Task Test_VersionStamp_Operations()
20072076 Log ( "Inserting keys with version stamps:" ) ;
20082077 using ( var tr = db . BeginTransaction ( this . Cancellation ) )
20092078 {
2010- //TODO: HACKACK: until we add support to he transaction itself, we have to 'patch' the versionstamps by hand!
2011- Slice HACKHACK_Stampify ( Slice key )
2012- {
2013- // find the stamp byte sequence in the key
2014- var x = tr . CreateVersionStamp ( ) . ToSlice ( ) ;
2015- int p = key . IndexOf ( x ) ;
2016- Assert . That ( p , Is . GreaterThan ( 0 ) , "Stamp pattern was not found in the key!" ) ;
2017-
2018- // append the offset at the end
2019- var writer = new SliceWriter ( key . Count + 2 ) ;
2020- writer . WriteBytes ( key ) ;
2021- writer . WriteFixed16 ( ( ushort ) p ) ; //note: the offset is Little Endian!
2022- var y = writer . ToSlice ( ) ;
2023-
2024- //Log(y.ToHexaString(' ') + " | " + location.Keys.Dump(y));
2025- return y ;
2026- }
20272079
2080+ // should return a 80-bit incomplete stamp, using a random token
20282081 var vs = tr . CreateVersionStamp ( ) ;
20292082 Log ( $ "> placeholder stamp: { vs } with token '{ vs . ToSlice ( ) : X} '") ;
2030- Assert . That ( vs . IsIncomplete , Is . True , "Placeholder token should be incomplete" ) ;
2031- Assert . That ( vs . HasUserVersion , Is . False ) ;
2032- Assert . That ( vs . UserVersion , Is . Zero ) ;
2033- Assert . That ( vs . TransactionVersion >> 56 , Is . EqualTo ( 0xFF ) , "Highest 8 bit of Transaction Version should be set to 1" ) ;
2034- Assert . That ( vs . TransactionOrder >> 12 , Is . EqualTo ( 0xF ) , "Hight 4 bits of Transaction Order should be set to 1" ) ;
2035-
2036- var vs0 = tr . CreateVersionStamp ( 0 ) ;
2037- Assert . That ( vs0 . IsIncomplete , Is . True , "Placeholder token should be incomplete" ) ;
2038- Assert . That ( vs0 . TransactionVersion , Is . EqualTo ( vs . TransactionVersion ) , "All generated stamps by one transaction should share the random token value " ) ;
2039- Assert . That ( vs0 . TransactionOrder , Is . EqualTo ( vs . TransactionOrder ) , "All generated stamps by one transaction should share the random token value " ) ;
2040- Assert . That ( vs0 . HasUserVersion , Is . True ) ;
2041- Assert . That ( vs0 . UserVersion , Is . EqualTo ( 0 ) ) ;
2042-
2043- var vs1 = tr . CreateVersionStamp ( 1 ) ;
2044- Assert . That ( vs1 . IsIncomplete , Is . True , "Placeholder token should be incomplete" ) ;
2045- Assert . That ( vs1 . TransactionVersion , Is . EqualTo ( vs . TransactionVersion ) , "All generated stamps by one transaction should share the random token value " ) ;
2046- Assert . That ( vs1 . TransactionOrder , Is . EqualTo ( vs . TransactionOrder ) , "All generated stamps by one transaction should share the random token value " ) ;
2047- Assert . That ( vs1 . HasUserVersion , Is . True ) ;
2048- Assert . That ( vs1 . UserVersion , Is . EqualTo ( 1 ) ) ;
2049-
2050- var vs42 = tr . CreateVersionStamp ( 42 ) ;
2051- Assert . That ( vs42 . IsIncomplete , Is . True , "Placeholder token should be incomplete" ) ;
2052- Assert . That ( vs42 . TransactionVersion , Is . EqualTo ( vs . TransactionVersion ) , "All generated stamps by one transaction should share the random token value " ) ;
2053- Assert . That ( vs42 . TransactionOrder , Is . EqualTo ( vs . TransactionOrder ) , "All generated stamps by one transaction should share the random token value " ) ;
2054- Assert . That ( vs42 . HasUserVersion , Is . True ) ;
2055- Assert . That ( vs42 . UserVersion , Is . EqualTo ( 42 ) ) ;
20562083
20572084 // a single key using the 80-bit stamp
2058- tr . SetVersionStampedKey ( HACKHACK_Stampify ( location . Keys . Encode ( "foo" , vs , 123 ) ) , Slice . FromString ( "Hello, World!" ) ) ;
2085+ tr . SetVersionStampedKey ( location . Keys . Encode ( "foo" , vs , 123 ) , Slice . FromString ( "Hello, World!" ) ) ;
20592086
20602087 // simulate a batch of 3 keys, using 96-bits stamps
2061- tr . SetVersionStampedKey ( HACKHACK_Stampify ( location . Keys . Encode ( "bar" , vs0 ) ) , Slice . FromString ( "Zero" ) ) ;
2062- tr . SetVersionStampedKey ( HACKHACK_Stampify ( location . Keys . Encode ( "bar" , vs1 ) ) , Slice . FromString ( "One" ) ) ;
2063- tr . SetVersionStampedKey ( HACKHACK_Stampify ( location . Keys . Encode ( "bar" , vs42 ) ) , Slice . FromString ( "FortyTwo" ) ) ;
2088+ tr . SetVersionStampedKey ( location . Keys . Encode ( "bar" , tr . CreateVersionStamp ( 0 ) ) , Slice . FromString ( "Zero" ) ) ;
2089+ tr . SetVersionStampedKey ( location . Keys . Encode ( "bar" , tr . CreateVersionStamp ( 1 ) ) , Slice . FromString ( "One" ) ) ;
2090+ tr . SetVersionStampedKey ( location . Keys . Encode ( "bar" , tr . CreateVersionStamp ( 42 ) ) , Slice . FromString ( "FortyTwo" ) ) ;
2091+
2092+ // value that contain the stamp
2093+ var val = Slice . FromString ( "$$$$$$$$$$Hello World!" ) ; // '$' will be replaced by the stamp
2094+ Log ( $ "> { val : X} ") ;
2095+ tr . SetVersionStampedValue ( location . Keys . Encode ( "baz" ) , val ) ;
20642096
20652097 // need to be request BEFORE the commit
20662098 var vsTask = tr . GetVersionStampAsync ( ) ;
@@ -2073,6 +2105,8 @@ Slice HACKHACK_Stampify(Slice key)
20732105 Log ( $ "> actual stamp: { vsActual } with token '{ vsActual . ToSlice ( ) : X} '") ;
20742106 }
20752107
2108+ await DumpSubspace ( db , location ) ;
2109+
20762110 Log ( "Checking database content:" ) ;
20772111 using ( var tr = db . BeginReadOnlyTransaction ( this . Cancellation ) )
20782112 {
@@ -2128,9 +2162,17 @@ Slice HACKHACK_Stampify(Slice key)
21282162 Assert . That ( vs42 . TransactionVersion , Is . EqualTo ( vsActual . TransactionVersion ) ) ;
21292163 Assert . That ( vs42 . TransactionOrder , Is . EqualTo ( vsActual . TransactionOrder ) ) ;
21302164 }
2165+
2166+ {
2167+ var baz = await tr . GetAsync ( location . Keys . Encode ( "baz" ) ) ;
2168+ Log ( $ "> { baz : X} ") ;
2169+ // ensure that the first 10 bytes have been overwritten with the stamp
2170+ Assert . That ( baz . Count , Is . GreaterThan ( 0 ) , "Key should be present in the database" ) ;
2171+ Assert . That ( baz . StartsWith ( vsActual . ToSlice ( ) ) , Is . True , "The first 10 bytes should match the resolved stamp" ) ;
2172+ Assert . That ( baz . Substring ( 10 ) , Is . EqualTo ( Slice . FromString ( "Hello World!" ) ) , "The rest of the slice should be untouched" ) ;
2173+ }
21312174 }
21322175
2133- await DumpSubspace ( db , location ) ;
21342176 }
21352177 }
21362178
0 commit comments