Skip to content

Commit e34c09b

Browse files
committed
impl: backends registry, KvsMap backend params
- Added `KvsBackendRegistry`. - `KvsBuilder` accepts backend params through `KvsMap`. - Built-in backend access is now hidden. - `backend_registration` example. - PlantUML-based class diagram.
1 parent 3ffbfaf commit e34c09b

File tree

19 files changed

+884
-407
lines changed

19 files changed

+884
-407
lines changed

README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,6 @@ Snapshot Count:
183183
Snapshot Restore:
184184
kvs_tool -o snapshotrestore -s 1
185185
186-
Get KVS Filename:
187-
kvs_tool -o getkvsfilename -s 1
188-
189-
Get Hash Filename:
190-
kvs_tool -o gethashfilename -s 1
191-
192186
---------------------------------------
193187
194188
Create Test Data:

docs/class_diagram.puml

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
@startuml Persistency class diagram
2+
3+
package "kvs_builder" {
4+
~class KvsInner {
5+
~parameters: KvsParameters
6+
~data: KvsData
7+
}
8+
9+
+class KvsBuilder {
10+
{static} -KVS_POOL: list<KvsInner>
11+
-parameters: KvsParameters
12+
13+
+new(instance_id: InstanceId): KvsBuilder
14+
{static} +max_instances(): usize
15+
+defaults(mode: KvsDefaults): KvsBuilder
16+
+kvs_load(mode: KvsLoad): KvsBuilder
17+
+backend_parameters(parameters: KvsMap): KvsBuilder
18+
+build(): Kvs
19+
}
20+
21+
KvsInner <-- KvsBuilder
22+
}
23+
24+
package "kvs_api" {
25+
+interface KvsApi {
26+
+reset()
27+
+reset_key(key: string)
28+
+get_all_keys(): list<string>
29+
+key_exists(key: string): bool
30+
+get_value(key: string): KvsValue
31+
+get_value_as<T>(key: string): T
32+
+get_default_value(key: string): KvsValue
33+
+is_value_default(key: string): bool
34+
+set_value<T>(key: string, value: T)
35+
+remove_key(key: string)
36+
+flush()
37+
+snapshot_count(): usize
38+
+snapshot_max_count(): usize
39+
+snapshot_restore(snapshot_id: SnapshotId)
40+
}
41+
}
42+
43+
package "kvs" {
44+
+class Kvs {
45+
-data: KvsData
46+
-parameters: KvsParameters
47+
-backend: KvsBackend
48+
49+
~new(data: KvsData, parameters: KvsParameters, backend: KvsBackend): Kvs
50+
+parameters(): KvsParameters
51+
52+
+reset()
53+
+reset_key(key: string)
54+
+get_all_keys(): list<string>
55+
+key_exists(key: string): bool
56+
+get_value(key: string): KvsValue
57+
+get_value_as<T>(key: string): T
58+
+get_default_value(key: string): KvsValue
59+
+is_value_default(key: string): bool
60+
+set_value<T>(key: string, value: T)
61+
+remove_key(key: string)
62+
+flush()
63+
+snapshot_count(): usize
64+
+snapshot_max_count(): usize
65+
+snapshot_restore(snapshot_id: SnapshotId)
66+
}
67+
}
68+
69+
KvsApi <|.. Kvs
70+
KvsBuilder -- Kvs
71+
72+
package "kvs_backend_registry" {
73+
+class KvsBackendRegistry {
74+
{static} -REGISTERED_BACKENDS: map<string, KvsBackendFactory>
75+
76+
{static} ~from_name(name: string) -> Result<&Box<dyn KvsBackendFactory>, ErrorCode>
77+
{static} ~from_parameters(parameters: KvsMap) -> Result<&Box<dyn KvsBackendFactory>, ErrorCode>
78+
79+
{static} +register(backend_factory: KvsBackendFactory)
80+
}
81+
}
82+
83+
KvsBackendRegistry .. KvsBuilder
84+
85+
package "kvs_backend" {
86+
+interface KvsBackend {
87+
+load_kvs(instance_id: InstanceId, snapshot_id: SnapshotId): KvsMap
88+
+load_defaults(instance_id: InstanceId): KvsMap
89+
+flush(instance_id: InstanceId, kvs_map: KvsMap)
90+
+snapshot_count(instance_id: InstanceId): usize
91+
+snapshot_max_count(): usize
92+
+snapshot_restore(instance_id: InstanceId, snapshot_id: SnapshotId): KvsMap
93+
}
94+
95+
+interface KvsBackendFactory {
96+
+create(parameters: KvsMap): KvsBackend
97+
}
98+
}
99+
100+
package "json_backend" {
101+
~class JsonBackend {
102+
+load_kvs(instance_id: InstanceId, snapshot_id: SnapshotId): KvsMap
103+
+load_defaults(instance_id: InstanceId): KvsMap
104+
+flush(instance_id: InstanceId, kvs_map: KvsMap)
105+
+snapshot_count(instance_id: InstanceId): usize
106+
+snapshot_max_count(): usize
107+
+snapshot_restore(instance_id: InstanceId, snapshot_id: SnapshotId): KvsMap
108+
}
109+
110+
~class JsonBackendFactory {
111+
+create(parameters: KvsMap): KvsBackend
112+
}
113+
}
114+
115+
KvsBackend <-- Kvs
116+
117+
KvsBackendRegistry --> KvsBackendFactory
118+
KvsBackendFactory -- KvsBackend
119+
120+
KvsBackend <|.. JsonBackend
121+
KvsBackendFactory <|.. JsonBackendFactory
122+
JsonBackendFactory -- JsonBackend
123+
124+
@enduml
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//! Example for custom backend registration.
2+
//! - Implementation of `KvsBackend` traits.
3+
//! - Registration of custom backend.
4+
//! - Creation of KVS instance utilizing custom backend.
5+
6+
use rust_kvs::prelude::*;
7+
use tempfile::tempdir;
8+
9+
/// Mock backend implementation.
10+
/// Only `load_kvs` is implemented.
11+
struct MockBackend;
12+
13+
impl KvsBackend for MockBackend {
14+
fn load_kvs(
15+
&self,
16+
_instance_id: InstanceId,
17+
_snapshot_id: SnapshotId,
18+
) -> Result<KvsMap, ErrorCode> {
19+
println!("`load_kvs` used");
20+
Ok(KvsMap::new())
21+
}
22+
23+
fn load_defaults(&self, _instance_id: InstanceId) -> Result<KvsMap, ErrorCode> {
24+
unimplemented!()
25+
}
26+
27+
fn flush(&self, _instance_id: InstanceId, _kvs_map: &KvsMap) -> Result<(), ErrorCode> {
28+
unimplemented!()
29+
}
30+
31+
fn snapshot_count(&self, _instance_id: InstanceId) -> usize {
32+
unimplemented!()
33+
}
34+
35+
fn snapshot_max_count(&self) -> usize {
36+
unimplemented!()
37+
}
38+
39+
fn snapshot_restore(
40+
&self,
41+
_instance_id: InstanceId,
42+
_snapshot_id: SnapshotId,
43+
) -> Result<KvsMap, ErrorCode> {
44+
unimplemented!()
45+
}
46+
}
47+
48+
/// Mock backend factory implementation.
49+
struct MockBackendFactory;
50+
51+
impl KvsBackendFactory for MockBackendFactory {
52+
fn create(&self, _parameters: &KvsMap) -> Result<Box<dyn KvsBackend>, ErrorCode> {
53+
Ok(Box::new(MockBackend))
54+
}
55+
}
56+
57+
fn main() -> Result<(), ErrorCode> {
58+
// Temporary directory.
59+
let dir = tempdir()?;
60+
let dir_string = dir.path().to_string_lossy().to_string();
61+
62+
// Register `MockBackendFactory`.
63+
KvsBackendRegistry::register("mock", || Box::new(MockBackendFactory))?;
64+
65+
// Build KVS instance with mock backend.
66+
{
67+
let instance_id = InstanceId(0);
68+
let parameters = KvsMap::from([("name".to_string(), KvsValue::String("mock".to_string()))]);
69+
let builder = KvsBuilder::new(instance_id)
70+
.backend_parameters(parameters)
71+
.defaults(KvsDefaults::Ignored);
72+
let kvs = builder.build()?;
73+
74+
println!(
75+
"KVS instance with mock backend - parameters: {:?}",
76+
kvs.parameters()
77+
);
78+
}
79+
80+
// Build KVS instance with JSON backend - default parameters.
81+
{
82+
let instance_id = InstanceId(1);
83+
let builder = KvsBuilder::new(instance_id).defaults(KvsDefaults::Ignored);
84+
let kvs = builder.build()?;
85+
86+
println!(
87+
"KVS instance with default JSON backend - parameters: {:?}",
88+
kvs.parameters()
89+
);
90+
}
91+
92+
// Build KVS instance with JSON backend - `working_dir` set.
93+
{
94+
let instance_id = InstanceId(2);
95+
let parameters = KvsMap::from([
96+
("name".to_string(), KvsValue::String("json".to_string())),
97+
("working_dir".to_string(), KvsValue::String(dir_string)),
98+
]);
99+
let builder = KvsBuilder::new(instance_id)
100+
.backend_parameters(parameters)
101+
.defaults(KvsDefaults::Ignored);
102+
let kvs = builder.build()?;
103+
104+
println!(
105+
"KVS instance with JSON backend - parameters: {:?}",
106+
kvs.parameters()
107+
);
108+
}
109+
110+
Ok(())
111+
}

src/rust/rust_kvs/examples/basic.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ use std::collections::HashMap;
88
use tempfile::tempdir;
99

1010
fn main() -> Result<(), ErrorCode> {
11-
// Temporary directory and common backend.
11+
// Temporary directory.
1212
let dir = tempdir()?;
13-
let dir_path = dir.path().to_path_buf();
14-
let backend = Box::new(JsonBackendBuilder::new().working_dir(dir_path).build());
13+
let dir_string = dir.path().to_string_lossy().to_string();
14+
let backend_parameters = KvsMap::from([
15+
("name".to_string(), KvsValue::String("json".to_string())),
16+
("working_dir".to_string(), KvsValue::String(dir_string)),
17+
]);
1518

1619
// Instance ID for KVS object instances.
1720
let instance_id = InstanceId(0);
@@ -21,7 +24,7 @@ fn main() -> Result<(), ErrorCode> {
2124
// `kvs_load` is explicitly set to `KvsLoad::Optional`, but this is the default value.
2225
// KVS files are not required.
2326
let builder = KvsBuilder::new(instance_id)
24-
.backend(backend.clone())
27+
.backend_parameters(backend_parameters.clone())
2528
.kvs_load(KvsLoad::Optional);
2629
let kvs = builder.build()?;
2730

@@ -66,7 +69,7 @@ fn main() -> Result<(), ErrorCode> {
6669
// Build KVS instance for given instance ID and temporary directory.
6770
// `kvs_load` is set to `KvsLoad::Required` - KVS files must already exist from previous KVS instance.
6871
let builder = KvsBuilder::new(instance_id)
69-
.backend(backend)
72+
.backend_parameters(backend_parameters)
7073
.kvs_load(KvsLoad::Required);
7174
let kvs = builder.build()?;
7275

src/rust/rust_kvs/examples/defaults.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,13 @@ fn create_defaults_file(dir_path: PathBuf, instance_id: InstanceId) -> Result<()
3131
}
3232

3333
fn main() -> Result<(), ErrorCode> {
34-
// Temporary directory and common backend.
34+
// Temporary directory.
3535
let dir = tempdir()?;
36-
let dir_path = dir.path().to_path_buf();
37-
let backend = Box::new(JsonBackendBuilder::new().working_dir(dir_path).build());
36+
let dir_string = dir.path().to_string_lossy().to_string();
37+
let backend_parameters = KvsMap::from([
38+
("name".to_string(), KvsValue::String("json".to_string())),
39+
("working_dir".to_string(), KvsValue::String(dir_string)),
40+
]);
3841

3942
// Instance ID for KVS object instances.
4043
let instance_id = InstanceId(0);
@@ -45,7 +48,7 @@ fn main() -> Result<(), ErrorCode> {
4548
// Build KVS instance for given instance ID and temporary directory.
4649
// `defaults` is set to `KvsDefaults::Required` - defaults are required.
4750
let builder = KvsBuilder::new(instance_id)
48-
.backend(backend.clone())
51+
.backend_parameters(backend_parameters)
4952
.defaults(KvsDefaults::Required);
5053
let kvs = builder.build()?;
5154

src/rust/rust_kvs/examples/snapshots.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ use tempfile::tempdir;
88
fn main() -> Result<(), ErrorCode> {
99
// Temporary directory and common backend.
1010
let dir = tempdir()?;
11-
let dir_path = dir.path().to_path_buf();
12-
let backend = Box::new(JsonBackendBuilder::new().working_dir(dir_path).build());
11+
let dir_string = dir.path().to_string_lossy().to_string();
12+
let backend_parameters = KvsMap::from([
13+
("name".to_string(), KvsValue::String("json".to_string())),
14+
("working_dir".to_string(), KvsValue::String(dir_string)),
15+
]);
1316

1417
// Instance ID for KVS object instances.
1518
let instance_id = InstanceId(0);
@@ -18,7 +21,7 @@ fn main() -> Result<(), ErrorCode> {
1821
println!("-> `snapshot_count` and `snapshot_max_count` usage");
1922

2023
// Build KVS instance for given instance ID and temporary directory.
21-
let builder = KvsBuilder::new(instance_id).backend(backend.clone());
24+
let builder = KvsBuilder::new(instance_id).backend_parameters(backend_parameters.clone());
2225
let kvs = builder.build()?;
2326

2427
let max_count = kvs.snapshot_max_count() as u32;
@@ -39,7 +42,7 @@ fn main() -> Result<(), ErrorCode> {
3942
println!("-> `snapshot_restore` usage");
4043

4144
// Build KVS instance for given instance ID and temporary directory.
42-
let builder = KvsBuilder::new(instance_id).backend(backend.clone());
45+
let builder = KvsBuilder::new(instance_id).backend_parameters(backend_parameters);
4346
let kvs = builder.build()?;
4447

4548
let max_count = kvs.snapshot_max_count() as u32;

src/rust/rust_kvs/src/error_code.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ pub enum ErrorCode {
8282

8383
/// Instance parameters mismatch
8484
InstanceParametersMismatch,
85+
86+
/// Requested unknown backend
87+
UnknownBackend,
88+
89+
/// Backend already registered
90+
BackendAlreadyRegistered,
91+
92+
/// Invalid backend parameters.
93+
InvalidBackendParameters,
8594
}
8695

8796
impl From<std::io::Error> for ErrorCode {

0 commit comments

Comments
 (0)