Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F73645
namespace.rs
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
24 KB
Subscribers
None
namespace.rs
View Options
// This module implements "namespaces" which are buckets of unique values
// that maps to keys elsewhere in storage.
//
// the `names` tree is a k/v of `name` -> `id` where `id` is a u64 from `generate_id`.
// the `spaces` tree is a k/v of `id` -> `name` where `id` is a u64 the `names` tree id and `name` is a str.
use
crate
::
Result
;
use
crate
::
Error
;
use
sled
::
Transactional
;
#[derive(Debug, Clone)]
pub
struct
NamespaceStore
{
pub
(
crate
)
names
:
sled
::
Tree
,
pub
(
crate
)
spaces
:
sled
::
Tree
,
}
impl
NamespaceStore
{
pub
fn
open
(
db
:
&
sled
::
Db
)
->
Result
<
Self
>
{
Ok
(
NamespaceStore
{
names
:
db
.
open_tree
(
"namespaces/1/names"
)
?
,
spaces
:
db
.
open_tree
(
"namespaces/1/spaces"
)
?
,
})
}
/// Reserve a key in a namespace within an existing transaction context
pub
fn
reserve_in_transaction
(
&
self
,
names
:
&
sled
::
transaction
::
TransactionalTree
,
spaces
:
&
sled
::
transaction
::
TransactionalTree
,
namespace
:
&
str
,
key
:
&
str
,
value
:
&
str
,
)
->
sled
::
transaction
::
ConflictableTransactionResult
<
bool
,
()
>
{
// Get ID of the namespace from `names`
let
namespace_id
=
match
names
.
get
(
namespace
)
?
{
Some
(
id_bytes
)
=>
{
let
id_array
:
[
u8
;
8
]
=
id_bytes
.
as_ref
().
try_into
()
.
map_err
(
|
_
|
sled
::
transaction
::
ConflictableTransactionError
::
Abort
(()))
?
;
u64
::
from_be_bytes
(
id_array
)
}
None
=>
return
Err
(
sled
::
transaction
::
ConflictableTransactionError
::
Abort
(())),
};
// Create composite key: namespace_id + key
let
mut
composite_key
=
Vec
::
new
();
composite_key
.
extend_from_slice
(
&
namespace_id
.
to_be_bytes
());
composite_key
.
extend_from_slice
(
key
.
as_bytes
());
// Check if key already exists
if
spaces
.
get
(
&
composite_key
)
?
.
is_some
()
{
return
Err
(
sled
::
transaction
::
ConflictableTransactionError
::
Abort
(()));
}
// Insert the key-value pair
spaces
.
insert
(
composite_key
,
value
.
as_bytes
())
?
;
Ok
(
true
)
}
/// Get a value from a namespace within an existing transaction context
pub
fn
get_in_transaction
(
&
self
,
names
:
&
sled
::
transaction
::
TransactionalTree
,
spaces
:
&
sled
::
transaction
::
TransactionalTree
,
namespace
:
&
str
,
key
:
&
str
,
)
->
sled
::
transaction
::
ConflictableTransactionResult
<
Option
<
String
>
,
()
>
{
// Get ID of the namespace from `names`
let
namespace_id
=
match
names
.
get
(
namespace
)
?
{
Some
(
id_bytes
)
=>
{
let
id_array
:
[
u8
;
8
]
=
id_bytes
.
as_ref
().
try_into
()
.
map_err
(
|
_
|
sled
::
transaction
::
ConflictableTransactionError
::
Abort
(()))
?
;
u64
::
from_be_bytes
(
id_array
)
}
None
=>
return
Ok
(
None
),
// namespace doesn't exist
};
// Create composite key: namespace_id + key
let
mut
composite_key
=
Vec
::
new
();
composite_key
.
extend_from_slice
(
&
namespace_id
.
to_be_bytes
());
composite_key
.
extend_from_slice
(
key
.
as_bytes
());
// Get value from spaces
match
spaces
.
get
(
&
composite_key
)
?
{
Some
(
value_bytes
)
=>
{
let
value
=
String
::
from_utf8
(
value_bytes
.
to_vec
())
.
map_err
(
|
_
|
sled
::
transaction
::
ConflictableTransactionError
::
Abort
(()))
?
;
Ok
(
Some
(
value
))
}
None
=>
Ok
(
None
),
}
}
/// Remove a key from a namespace within an existing transaction context
pub
fn
remove_in_transaction
(
&
self
,
names
:
&
sled
::
transaction
::
TransactionalTree
,
spaces
:
&
sled
::
transaction
::
TransactionalTree
,
namespace
:
&
str
,
key
:
&
str
,
)
->
sled
::
transaction
::
ConflictableTransactionResult
<
bool
,
()
>
{
// Get ID of the namespace from `names`
let
namespace_id
=
match
names
.
get
(
namespace
)
?
{
Some
(
id_bytes
)
=>
{
let
id_array
:
[
u8
;
8
]
=
id_bytes
.
as_ref
().
try_into
()
.
map_err
(
|
_
|
sled
::
transaction
::
ConflictableTransactionError
::
Abort
(()))
?
;
u64
::
from_be_bytes
(
id_array
)
}
None
=>
return
Ok
(
false
),
// namespace doesn't exist
};
// Create composite key: namespace_id + key
let
mut
composite_key
=
Vec
::
new
();
composite_key
.
extend_from_slice
(
&
namespace_id
.
to_be_bytes
());
composite_key
.
extend_from_slice
(
key
.
as_bytes
());
// Remove the key-value pair
Ok
(
spaces
.
remove
(
composite_key
)
?
.
is_some
())
}
/// Update a key in a namespace within an existing transaction context
/// Returns true if the key existed and was updated, false if it didn't exist
pub
fn
update_in_transaction
(
&
self
,
names
:
&
sled
::
transaction
::
TransactionalTree
,
spaces
:
&
sled
::
transaction
::
TransactionalTree
,
namespace
:
&
str
,
key
:
&
str
,
value
:
&
str
,
)
->
sled
::
transaction
::
ConflictableTransactionResult
<
bool
,
()
>
{
// Get ID of the namespace from `names`
let
namespace_id
=
match
names
.
get
(
namespace
)
?
{
Some
(
id_bytes
)
=>
{
let
id_array
:
[
u8
;
8
]
=
id_bytes
.
as_ref
().
try_into
()
.
map_err
(
|
_
|
sled
::
transaction
::
ConflictableTransactionError
::
Abort
(()))
?
;
u64
::
from_be_bytes
(
id_array
)
}
None
=>
return
Ok
(
false
),
// namespace doesn't exist
};
// Create composite key: namespace_id + key
let
mut
composite_key
=
Vec
::
new
();
composite_key
.
extend_from_slice
(
&
namespace_id
.
to_be_bytes
());
composite_key
.
extend_from_slice
(
key
.
as_bytes
());
// Check if key exists and update it
match
spaces
.
get
(
&
composite_key
)
?
{
Some
(
_
)
=>
{
spaces
.
insert
(
composite_key
,
value
.
as_bytes
())
?
;
Ok
(
true
)
}
None
=>
Ok
(
false
),
}
}
/// Check if a namespace exists within an existing transaction context
pub
fn
namespace_exists_in_transaction
(
&
self
,
names
:
&
sled
::
transaction
::
TransactionalTree
,
namespace
:
&
str
,
)
->
sled
::
transaction
::
ConflictableTransactionResult
<
bool
,
()
>
{
Ok
(
names
.
get
(
namespace
)
?
.
is_some
())
}
/// Check if a key exists in a namespace within an existing transaction context
pub
fn
key_exists_in_transaction
(
&
self
,
names
:
&
sled
::
transaction
::
TransactionalTree
,
spaces
:
&
sled
::
transaction
::
TransactionalTree
,
namespace
:
&
str
,
key
:
&
str
,
)
->
sled
::
transaction
::
ConflictableTransactionResult
<
bool
,
()
>
{
// Get ID of the namespace from `names`
let
namespace_id
=
match
names
.
get
(
namespace
)
?
{
Some
(
id_bytes
)
=>
{
let
id_array
:
[
u8
;
8
]
=
id_bytes
.
as_ref
().
try_into
()
.
map_err
(
|
_
|
sled
::
transaction
::
ConflictableTransactionError
::
Abort
(()))
?
;
u64
::
from_be_bytes
(
id_array
)
}
None
=>
return
Ok
(
false
),
// namespace doesn't exist
};
// Create composite key: namespace_id + key
let
mut
composite_key
=
Vec
::
new
();
composite_key
.
extend_from_slice
(
&
namespace_id
.
to_be_bytes
());
composite_key
.
extend_from_slice
(
key
.
as_bytes
());
Ok
(
spaces
.
get
(
&
composite_key
)
?
.
is_some
())
}
// define a namespace.
// inserts a key `namespace` into `names`, where the value is a random u64.
pub
fn
define
(
&
self
,
namespace
:
&
str
)
->
Result
<
()
>
{
self
.
names
.
transaction
(
|
db
|
{
match
db
.
get
(
namespace
)
?
{
Some
(
_
)
=>
Ok
(()),
None
=>
{
let
id
=
db
.
generate_id
()
?
;
db
.
insert
(
namespace
,
&
id
.
to_be_bytes
())
?
;
Ok
(())
}
}
})
?
;
Ok
(())
}
pub
fn
resolve
(
&
self
,
namespace
:
&
str
,
key
:
&
str
)
->
Result
<
Option
<
String
>>
{
let
result
=
(
&
self
.
names
,
&
self
.
spaces
).
transaction
(
|
(
names
,
spaces
)
|
{
self
.
get_in_transaction
(
names
,
spaces
,
namespace
,
key
)
}).
map_err
(
|
e
|
match
e
{
sled
::
transaction
::
TransactionError
::
Abort
(())
=>
Error
::
UndefinedNamespace
(
namespace
.
to_string
()),
sled
::
transaction
::
TransactionError
::
Storage
(
storage_err
)
=>
Error
::
StoreError
(
storage_err
),
})
?
;
Ok
(
result
)
}
pub
fn
reserve
(
&
self
,
namespace
:
&
str
,
key
:
&
str
,
value
:
&
str
)
->
Result
<
bool
>
{
let
result
=
(
&
self
.
names
,
&
self
.
spaces
).
transaction
(
|
(
names
,
spaces
)
|
{
self
.
reserve_in_transaction
(
names
,
spaces
,
namespace
,
key
,
value
)
}).
map_err
(
|
e
|
match
e
{
sled
::
transaction
::
TransactionError
::
Abort
(())
=>
Error
::
NamespaceKeyReserved
(
namespace
.
to_string
(),
key
.
to_string
()),
sled
::
transaction
::
TransactionError
::
Storage
(
storage_err
)
=>
Error
::
StoreError
(
storage_err
),
})
?
;
Ok
(
result
)
}
pub
fn
get
(
&
self
,
namespace
:
&
str
,
key
:
&
str
)
->
Result
<
Option
<
String
>>
{
let
result
=
(
&
self
.
names
,
&
self
.
spaces
).
transaction
(
|
(
names
,
spaces
)
|
{
self
.
get_in_transaction
(
names
,
spaces
,
namespace
,
key
)
}).
map_err
(
|
e
|
match
e
{
sled
::
transaction
::
TransactionError
::
Abort
(())
=>
Error
::
StoreError
(
sled
::
Error
::
Unsupported
(
"Transaction aborted"
.
to_string
())),
sled
::
transaction
::
TransactionError
::
Storage
(
storage_err
)
=>
Error
::
StoreError
(
storage_err
),
})
?
;
Ok
(
result
)
}
pub
fn
remove
(
&
self
,
namespace
:
&
str
,
key
:
&
str
)
->
Result
<
bool
>
{
let
result
=
(
&
self
.
names
,
&
self
.
spaces
).
transaction
(
|
(
names
,
spaces
)
|
{
self
.
remove_in_transaction
(
names
,
spaces
,
namespace
,
key
)
}).
map_err
(
|
e
|
match
e
{
sled
::
transaction
::
TransactionError
::
Abort
(())
=>
Error
::
StoreError
(
sled
::
Error
::
Unsupported
(
"Transaction aborted"
.
to_string
())),
sled
::
transaction
::
TransactionError
::
Storage
(
storage_err
)
=>
Error
::
StoreError
(
storage_err
),
})
?
;
Ok
(
result
)
}
/// Update a key in a namespace
pub
fn
update
(
&
self
,
namespace
:
&
str
,
key
:
&
str
,
value
:
&
str
)
->
Result
<
bool
>
{
let
result
=
(
&
self
.
names
,
&
self
.
spaces
).
transaction
(
|
(
names
,
spaces
)
|
{
self
.
update_in_transaction
(
names
,
spaces
,
namespace
,
key
,
value
)
}).
map_err
(
|
e
|
match
e
{
sled
::
transaction
::
TransactionError
::
Abort
(())
=>
Error
::
UndefinedNamespace
(
namespace
.
to_string
()),
sled
::
transaction
::
TransactionError
::
Storage
(
storage_err
)
=>
Error
::
StoreError
(
storage_err
),
})
?
;
Ok
(
result
)
}
/// Check if a namespace exists
pub
fn
namespace_exists
(
&
self
,
namespace
:
&
str
)
->
Result
<
bool
>
{
Ok
(
self
.
names
.
get
(
namespace
)
?
.
is_some
())
}
/// Check if a key exists in a namespace
pub
fn
key_exists
(
&
self
,
namespace
:
&
str
,
key
:
&
str
)
->
Result
<
bool
>
{
let
result
=
(
&
self
.
names
,
&
self
.
spaces
).
transaction
(
|
(
names
,
spaces
)
|
{
self
.
key_exists_in_transaction
(
names
,
spaces
,
namespace
,
key
)
}).
map_err
(
|
e
|
match
e
{
sled
::
transaction
::
TransactionError
::
Abort
(())
=>
Error
::
UndefinedNamespace
(
namespace
.
to_string
()),
sled
::
transaction
::
TransactionError
::
Storage
(
storage_err
)
=>
Error
::
StoreError
(
storage_err
),
})
?
;
Ok
(
result
)
}
/// List all defined namespaces
pub
fn
list_namespaces
(
&
self
)
->
Result
<
Vec
<
String
>>
{
let
mut
namespaces
=
Vec
::
new
();
for
result
in
self
.
names
.
iter
()
{
let
(
key
,
_
)
=
result
?
;
let
name
=
String
::
from_utf8
(
key
.
to_vec
())
?
;
namespaces
.
push
(
name
);
}
namespaces
.
sort
();
Ok
(
namespaces
)
}
/// List all keys in a namespace
pub
fn
list_keys
(
&
self
,
namespace
:
&
str
)
->
Result
<
Vec
<
String
>>
{
// Get namespace ID first
let
namespace_id
=
match
self
.
names
.
get
(
namespace
)
?
{
Some
(
id_bytes
)
=>
{
let
id_array
:
[
u8
;
8
]
=
id_bytes
.
as_ref
().
try_into
()
.
map_err
(
|
_
|
Error
::
StoreError
(
sled
::
Error
::
Unsupported
(
"Invalid namespace ID"
.
to_string
())))
?
;
u64
::
from_be_bytes
(
id_array
)
}
None
=>
return
Ok
(
Vec
::
new
()),
};
let
mut
keys
=
Vec
::
new
();
let
prefix
=
namespace_id
.
to_be_bytes
();
for
result
in
self
.
spaces
.
scan_prefix
(
&
prefix
)
{
let
(
key
,
_
)
=
result
?
;
if
key
.
len
()
>
8
{
let
key_part
=
&
key
[
8
..
];
let
key_str
=
String
::
from_utf8
(
key_part
.
to_vec
())
?
;
keys
.
push
(
key_str
);
}
}
keys
.
sort
();
Ok
(
keys
)
}
/// List all key-value pairs in a namespace
pub
fn
list_all
(
&
self
,
namespace
:
&
str
)
->
Result
<
Vec
<
(
String
,
String
)
>>
{
// Get namespace ID first
let
namespace_id
=
match
self
.
names
.
get
(
namespace
)
?
{
Some
(
id_bytes
)
=>
{
let
id_array
:
[
u8
;
8
]
=
id_bytes
.
as_ref
().
try_into
()
.
map_err
(
|
_
|
Error
::
StoreError
(
sled
::
Error
::
Unsupported
(
"Invalid namespace ID"
.
to_string
())))
?
;
u64
::
from_be_bytes
(
id_array
)
}
None
=>
return
Ok
(
Vec
::
new
()),
};
let
mut
pairs
=
Vec
::
new
();
let
prefix
=
namespace_id
.
to_be_bytes
();
for
result
in
self
.
spaces
.
scan_prefix
(
&
prefix
)
{
let
(
key
,
value
)
=
result
?
;
if
key
.
len
()
>
8
{
let
key_part
=
&
key
[
8
..
];
let
key_str
=
String
::
from_utf8
(
key_part
.
to_vec
())
?
;
let
value_str
=
String
::
from_utf8
(
value
.
to_vec
())
?
;
pairs
.
push
((
key_str
,
value_str
));
}
}
pairs
.
sort_by
(
|
a
,
b
|
a
.
0.
cmp
(
&
b
.
0
));
Ok
(
pairs
)
}
}
#[cfg(test)]
mod
tests
{
use
super
::
*
;
use
tempfile
::
tempdir
;
fn
create_test_store
()
->
Result
<
NamespaceStore
>
{
let
temp_dir
=
tempdir
().
unwrap
();
let
db
=
sled
::
open
(
temp_dir
.
path
())
?
;
NamespaceStore
::
open
(
&
db
)
}
#[test]
fn
test_define_namespace
()
->
Result
<
()
>
{
let
store
=
create_test_store
()
?
;
// Define a namespace
store
.
define
(
"test_namespace"
)
?
;
// Defining the same namespace again should not error
store
.
define
(
"test_namespace"
)
?
;
// Check that namespace exists
assert!
(
store
.
namespace_exists
(
"test_namespace"
)
?
);
assert!
(
!
store
.
namespace_exists
(
"nonexistent"
)
?
);
Ok
(())
}
#[test]
fn
test_reserve_and_get
()
->
Result
<
()
>
{
let
store
=
create_test_store
()
?
;
// Define namespace first
store
.
define
(
"test_namespace"
)
?
;
// Reserve a key
let
success
=
store
.
reserve
(
"test_namespace"
,
"test_key"
,
"test_value"
)
?
;
assert!
(
success
);
// Get the value
let
value
=
store
.
get
(
"test_namespace"
,
"test_key"
)
?
;
assert_eq!
(
value
,
Some
(
"test_value"
.
to_string
()));
// Check key exists
assert!
(
store
.
key_exists
(
"test_namespace"
,
"test_key"
)
?
);
assert!
(
!
store
.
key_exists
(
"test_namespace"
,
"nonexistent"
)
?
);
Ok
(())
}
#[test]
fn
test_reserve_duplicate_key
()
->
Result
<
()
>
{
let
store
=
create_test_store
()
?
;
// Define namespace first
store
.
define
(
"test_namespace"
)
?
;
// Reserve a key
store
.
reserve
(
"test_namespace"
,
"test_key"
,
"test_value"
)
?
;
// Try to reserve the same key again - should fail
let
result
=
store
.
reserve
(
"test_namespace"
,
"test_key"
,
"other_value"
);
assert!
(
result
.
is_err
());
Ok
(())
}
#[test]
fn
test_update
()
->
Result
<
()
>
{
let
store
=
create_test_store
()
?
;
// Define namespace first
store
.
define
(
"test_namespace"
)
?
;
// Reserve a key
store
.
reserve
(
"test_namespace"
,
"test_key"
,
"original_value"
)
?
;
// Update the key
let
updated
=
store
.
update
(
"test_namespace"
,
"test_key"
,
"new_value"
)
?
;
assert!
(
updated
);
// Verify the update
let
value
=
store
.
get
(
"test_namespace"
,
"test_key"
)
?
;
assert_eq!
(
value
,
Some
(
"new_value"
.
to_string
()));
// Try to update a non-existent key
let
not_updated
=
store
.
update
(
"test_namespace"
,
"nonexistent"
,
"value"
)
?
;
assert!
(
!
not_updated
);
Ok
(())
}
#[test]
fn
test_remove
()
->
Result
<
()
>
{
let
store
=
create_test_store
()
?
;
// Define namespace first
store
.
define
(
"test_namespace"
)
?
;
// Reserve a key
store
.
reserve
(
"test_namespace"
,
"test_key"
,
"test_value"
)
?
;
// Remove the key
let
removed
=
store
.
remove
(
"test_namespace"
,
"test_key"
)
?
;
assert!
(
removed
);
// Try to get the removed key
let
value
=
store
.
get
(
"test_namespace"
,
"test_key"
)
?
;
assert_eq!
(
value
,
None
);
// Check key no longer exists
assert!
(
!
store
.
key_exists
(
"test_namespace"
,
"test_key"
)
?
);
// Try to remove a non-existent key
let
removed_again
=
store
.
remove
(
"test_namespace"
,
"test_key"
)
?
;
assert!
(
!
removed_again
);
Ok
(())
}
#[test]
fn
test_list_operations
()
->
Result
<
()
>
{
let
store
=
create_test_store
()
?
;
// Define namespaces
store
.
define
(
"namespace1"
)
?
;
store
.
define
(
"namespace2"
)
?
;
// Add some data
store
.
reserve
(
"namespace1"
,
"key1"
,
"value1"
)
?
;
store
.
reserve
(
"namespace1"
,
"key2"
,
"value2"
)
?
;
store
.
reserve
(
"namespace1"
,
"key3"
,
"value3"
)
?
;
store
.
reserve
(
"namespace2"
,
"key1"
,
"different_value"
)
?
;
// Test list_namespaces
let
namespaces
=
store
.
list_namespaces
()
?
;
assert!
(
namespaces
.
contains
(
&
"namespace1"
.
to_string
()));
assert!
(
namespaces
.
contains
(
&
"namespace2"
.
to_string
()));
assert_eq!
(
namespaces
.
len
(),
2
);
// Test list_keys
let
keys
=
store
.
list_keys
(
"namespace1"
)
?
;
assert_eq!
(
keys
,
vec!
[
"key1"
,
"key2"
,
"key3"
]);
let
keys2
=
store
.
list_keys
(
"namespace2"
)
?
;
assert_eq!
(
keys2
,
vec!
[
"key1"
]);
// Test list_all
let
pairs
=
store
.
list_all
(
"namespace1"
)
?
;
assert_eq!
(
pairs
,
vec!
[
(
"key1"
.
to_string
(),
"value1"
.
to_string
()),
(
"key2"
.
to_string
(),
"value2"
.
to_string
()),
(
"key3"
.
to_string
(),
"value3"
.
to_string
()),
]);
Ok
(())
}
#[test]
fn
test_undefined_namespace
()
->
Result
<
()
>
{
let
store
=
create_test_store
()
?
;
// Try to get from undefined namespace
let
value
=
store
.
get
(
"undefined_namespace"
,
"test_key"
)
?
;
assert_eq!
(
value
,
None
);
// Try to remove from undefined namespace
let
removed
=
store
.
remove
(
"undefined_namespace"
,
"test_key"
)
?
;
assert!
(
!
removed
);
// Try to update in undefined namespace
let
updated
=
store
.
update
(
"undefined_namespace"
,
"test_key"
,
"value"
)
?
;
assert!
(
!
updated
);
// Check key exists returns false for undefined namespace
assert!
(
!
store
.
key_exists
(
"undefined_namespace"
,
"test_key"
)
?
);
Ok
(())
}
#[test]
fn
test_transaction_methods
()
->
Result
<
()
>
{
let
store
=
create_test_store
()
?
;
// Define namespace
store
.
define
(
"test_namespace"
)
?
;
// Test transaction methods
let
result
=
(
&
store
.
names
,
&
store
.
spaces
).
transaction
(
|
(
names
,
spaces
)
|
{
// Reserve in transaction
let
reserved
=
store
.
reserve_in_transaction
(
names
,
spaces
,
"test_namespace"
,
"key1"
,
"value1"
)
?
;
assert_eq!
(
reserved
,
true
);
// Get in transaction
let
value
=
store
.
get_in_transaction
(
names
,
spaces
,
"test_namespace"
,
"key1"
)
?
;
assert_eq!
(
value
,
Some
(
"value1"
.
to_string
()));
// Update in transaction
let
updated
=
store
.
update_in_transaction
(
names
,
spaces
,
"test_namespace"
,
"key1"
,
"new_value"
)
?
;
assert_eq!
(
updated
,
true
);
// Check key exists in transaction
let
exists
=
store
.
key_exists_in_transaction
(
names
,
spaces
,
"test_namespace"
,
"key1"
)
?
;
assert_eq!
(
exists
,
true
);
// Check key exists after update
let
exists_after_update
=
store
.
key_exists_in_transaction
(
names
,
spaces
,
"test_namespace"
,
"key1"
)
?
;
assert_eq!
(
exists_after_update
,
true
);
// Check namespace exists in transaction
let
ns_exists
=
store
.
namespace_exists_in_transaction
(
names
,
"test_namespace"
)
?
;
assert_eq!
(
ns_exists
,
true
);
// Remove in transaction
let
removed
=
store
.
remove_in_transaction
(
names
,
spaces
,
"test_namespace"
,
"key1"
)
?
;
assert_eq!
(
removed
,
true
);
Ok
(())
}).
map_err
(
|
e
|
match
e
{
sled
::
transaction
::
TransactionError
::
Abort
(())
=>
Error
::
StoreError
(
sled
::
Error
::
Unsupported
(
"Transaction aborted"
.
to_string
())),
sled
::
transaction
::
TransactionError
::
Storage
(
storage_err
)
=>
Error
::
StoreError
(
storage_err
),
})
?
;
Ok
(
result
)
}
#[test]
fn
test_transaction_rollback
()
->
Result
<
()
>
{
let
store
=
create_test_store
()
?
;
// Define namespace and add initial data
store
.
define
(
"test_namespace"
)
?
;
store
.
reserve
(
"test_namespace"
,
"existing_key"
,
"existing_value"
)
?
;
// Attempt a transaction that should fail
let
result
=
(
&
store
.
names
,
&
store
.
spaces
).
transaction
(
|
(
names
,
spaces
)
|
{
// This should succeed
let
_reserved
=
store
.
reserve_in_transaction
(
names
,
spaces
,
"test_namespace"
,
"new_key"
,
"new_value"
)
?
;
// This should fail (key already exists)
let
_duplicate
=
store
.
reserve_in_transaction
(
names
,
spaces
,
"test_namespace"
,
"existing_key"
,
"different_value"
)
?
;
Ok
(())
}).
map_err
(
|
e
|
match
e
{
sled
::
transaction
::
TransactionError
::
Abort
(())
=>
Error
::
NamespaceKeyReserved
(
"test_namespace"
.
to_string
(),
"existing_key"
.
to_string
()),
sled
::
transaction
::
TransactionError
::
Storage
(
storage_err
)
=>
Error
::
StoreError
(
storage_err
),
});
// Transaction should have failed
assert!
(
result
.
is_err
());
// Verify rollback - new_key should not exist
assert!
(
!
store
.
key_exists
(
"test_namespace"
,
"new_key"
)
?
);
// Existing key should still have original value
let
value
=
store
.
get
(
"test_namespace"
,
"existing_key"
)
?
;
assert_eq!
(
value
,
Some
(
"existing_value"
.
to_string
()));
Ok
(())
}
#[test]
fn
test_multiple_namespaces
()
->
Result
<
()
>
{
let
store
=
create_test_store
()
?
;
// Define multiple namespaces
store
.
define
(
"users"
)
?
;
store
.
define
(
"products"
)
?
;
store
.
define
(
"orders"
)
?
;
// Add data to each namespace
store
.
reserve
(
"users"
,
"alice"
,
"Alice Smith"
)
?
;
store
.
reserve
(
"users"
,
"bob"
,
"Bob Jones"
)
?
;
store
.
reserve
(
"products"
,
"laptop"
,
"MacBook Pro"
)
?
;
store
.
reserve
(
"products"
,
"mouse"
,
"Magic Mouse"
)
?
;
store
.
reserve
(
"orders"
,
"001"
,
"Alice's laptop order"
)
?
;
// Test isolation between namespaces
assert_eq!
(
store
.
get
(
"users"
,
"alice"
)
?
,
Some
(
"Alice Smith"
.
to_string
()));
assert_eq!
(
store
.
get
(
"products"
,
"laptop"
)
?
,
Some
(
"MacBook Pro"
.
to_string
()));
assert_eq!
(
store
.
get
(
"orders"
,
"001"
)
?
,
Some
(
"Alice's laptop order"
.
to_string
()));
// Keys with same name in different namespaces should be separate
store
.
reserve
(
"users"
,
"test"
,
"user_test"
)
?
;
store
.
reserve
(
"products"
,
"test"
,
"product_test"
)
?
;
assert_eq!
(
store
.
get
(
"users"
,
"test"
)
?
,
Some
(
"user_test"
.
to_string
()));
assert_eq!
(
store
.
get
(
"products"
,
"test"
)
?
,
Some
(
"product_test"
.
to_string
()));
// Verify namespace listing
let
namespaces
=
store
.
list_namespaces
()
?
;
assert!
(
namespaces
.
contains
(
&
"users"
.
to_string
()));
assert!
(
namespaces
.
contains
(
&
"products"
.
to_string
()));
assert!
(
namespaces
.
contains
(
&
"orders"
.
to_string
()));
Ok
(())
}
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jun 8, 7:17 AM (14 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
47566
Default Alt Text
namespace.rs (24 KB)
Attached To
rCOLLAR collar
Event Timeline
Log In to Comment