@@ -18,24 +18,29 @@ use std::collections::HashMap;
18
18
use std:: sync:: Arc ;
19
19
20
20
use cheetah_string:: CheetahString ;
21
+ use parking_lot:: RwLock ;
21
22
use rocketmq_common:: common:: namesrv:: namesrv_config:: NamesrvConfig ;
22
23
use rocketmq_common:: utils:: serde_json_utils:: SerdeJsonUtils ;
23
24
use rocketmq_common:: FileUtils ;
24
25
use rocketmq_remoting:: protocol:: body:: kv_table:: KVTable ;
25
26
use rocketmq_remoting:: protocol:: RemotingSerializable ;
27
+ use rocketmq_rust:: ArcMut ;
26
28
use tracing:: error;
27
29
use tracing:: info;
28
30
29
31
use crate :: kvconfig:: KVConfigSerializeWrapper ;
30
32
31
- #[ derive( Debug , Clone ) ]
33
+ #[ derive( Clone ) ]
32
34
pub struct KVConfigManager {
33
- pub ( crate ) config_table : HashMap <
34
- CheetahString , /* Namespace */
35
- HashMap < CheetahString /* Key */ , CheetahString /* Value */ > ,
35
+ pub ( crate ) config_table : Arc <
36
+ RwLock <
37
+ HashMap <
38
+ CheetahString , /* Namespace */
39
+ HashMap < CheetahString /* Key */ , CheetahString /* Value */ > ,
40
+ > ,
41
+ > ,
36
42
> ,
37
-
38
- pub ( crate ) namesrv_config : Arc < NamesrvConfig > ,
43
+ pub ( crate ) namesrv_config : ArcMut < NamesrvConfig > ,
39
44
}
40
45
41
46
impl KVConfigManager {
@@ -48,9 +53,9 @@ impl KVConfigManager {
48
53
/// # Returns
49
54
///
50
55
/// A new `KVConfigManager` instance.
51
- pub fn new ( namesrv_config : Arc < NamesrvConfig > ) -> KVConfigManager {
56
+ pub fn new ( namesrv_config : ArcMut < NamesrvConfig > ) -> KVConfigManager {
52
57
KVConfigManager {
53
- config_table : HashMap :: new ( ) ,
58
+ config_table : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
54
59
namesrv_config,
55
60
}
56
61
}
@@ -62,8 +67,8 @@ impl KVConfigManager {
62
67
/// A reference to the configuration table.
63
68
pub fn get_config_table (
64
69
& self ,
65
- ) -> & HashMap < CheetahString , HashMap < CheetahString , CheetahString > > {
66
- & self . config_table
70
+ ) -> HashMap < CheetahString , HashMap < CheetahString , CheetahString > > {
71
+ self . config_table . read ( ) . clone ( )
67
72
}
68
73
69
74
/// Gets a reference to the Namesrv configuration.
@@ -83,18 +88,18 @@ impl KVConfigManager {
83
88
if let Ok ( content) = result {
84
89
let wrapper =
85
90
SerdeJsonUtils :: decode :: < KVConfigSerializeWrapper > ( content. as_bytes ( ) ) . unwrap ( ) ;
86
- if let Some ( ref config_table) = wrapper. config_table {
87
- for ( namespace, config) in config_table {
88
- self . config_table . insert ( namespace. clone ( ) , config. clone ( ) ) ;
89
- }
91
+ if let Some ( config_table) = wrapper. config_table {
92
+ let mut table = self . config_table . write ( ) ;
93
+ table. extend ( config_table) ;
90
94
info ! ( "load KV config success" ) ;
91
95
}
92
96
}
93
97
}
94
98
95
99
/// Persists the current key-value configurations to a file.
96
100
pub fn persist ( & mut self ) {
97
- let wrapper = KVConfigSerializeWrapper :: new_with_config_table ( self . config_table . clone ( ) ) ;
101
+ let wrapper =
102
+ KVConfigSerializeWrapper :: new_with_config_table ( self . config_table . write ( ) . clone ( ) ) ;
98
103
let content = serde_json:: to_string ( & wrapper) . unwrap ( ) ;
99
104
100
105
let result = FileUtils :: string_to_file (
@@ -109,96 +114,157 @@ impl KVConfigManager {
109
114
/// Adds or updates a key-value configuration.
110
115
pub fn put_kv_config (
111
116
& mut self ,
112
- namespace : impl Into < CheetahString > ,
113
- key : impl Into < CheetahString > ,
114
- value : impl Into < CheetahString > ,
117
+ namespace : CheetahString ,
118
+ key : CheetahString ,
119
+ value : CheetahString ,
115
120
) {
116
- let namespace_inner = namespace. into ( ) ;
117
- if !self . config_table . contains_key ( namespace_inner. as_str ( ) ) {
118
- self . config_table
119
- . insert ( namespace_inner. clone ( ) , HashMap :: new ( ) ) ;
120
- }
121
-
122
- let key = key. into ( ) ;
123
- let value = value. into ( ) ;
124
- let pre_value = self
125
- . config_table
126
- . get_mut ( namespace_inner. as_str ( ) )
127
- . unwrap ( )
128
- . insert ( key. clone ( ) , value. clone ( ) ) ;
121
+ let mut config_table = self . config_table . write ( ) ;
122
+ let namespace_entry = config_table. entry ( namespace. clone ( ) ) . or_default ( ) ;
123
+ let pre_value = namespace_entry. insert ( key. clone ( ) , value. clone ( ) ) ;
129
124
match pre_value {
130
125
None => {
131
126
info ! (
132
127
"putKVConfig create new config item, Namespace: {} Key: {} Value: {}" ,
133
- namespace_inner , key, value
128
+ namespace , key, value
134
129
)
135
130
}
136
131
Some ( _) => {
137
132
info ! (
138
133
"putKVConfig update config item, Namespace: {} Key: {} Value: {}" ,
139
- namespace_inner , key, value
134
+ namespace , key, value
140
135
)
141
136
}
142
137
}
138
+ drop ( config_table) ;
143
139
self . persist ( ) ;
144
140
}
145
141
146
142
/// Deletes a key-value configuration.
147
- pub fn delete_kv_config ( & mut self , namespace : impl Into < String > , key : impl Into < String > ) {
148
- let namespace_inner = namespace . into ( ) ;
149
- if !self . config_table . contains_key ( namespace_inner . as_str ( ) ) {
143
+ pub fn delete_kv_config ( & mut self , namespace : & CheetahString , key : & CheetahString ) {
144
+ let mut config_table = self . config_table . write ( ) ;
145
+ if !config_table. contains_key ( namespace ) {
150
146
return ;
151
147
}
152
148
153
- let key = key. into ( ) ;
154
- let pre_value = self
155
- . config_table
156
- . get_mut ( namespace_inner. as_str ( ) )
157
- . unwrap ( )
158
- . remove ( key. as_str ( ) ) ;
149
+ let pre_value = config_table. get_mut ( namespace) . unwrap ( ) . remove ( key) ;
159
150
match pre_value {
160
151
None => { }
161
152
Some ( value) => {
162
153
info ! (
163
154
"deleteKVConfig delete a config item, Namespace: {} Key: {} Value: {}" ,
164
- namespace_inner , key, value
155
+ namespace , key, value
165
156
)
166
157
}
167
158
}
159
+ drop ( config_table) ;
168
160
self . persist ( ) ;
169
161
}
170
162
171
163
/// Gets the key-value list for a specific namespace.
172
- pub fn get_kv_list_by_namespace (
173
- & mut self ,
174
- namespace : impl Into < CheetahString > ,
175
- ) -> Option < Vec < u8 > > {
176
- let namespace_inner = namespace. into ( ) ;
177
- match self . config_table . get ( namespace_inner. as_str ( ) ) {
178
- None => None ,
179
- Some ( kv_table) => {
180
- let table = KVTable {
181
- table : kv_table. clone ( ) ,
182
- } ;
183
- Some ( table. encode ( ) )
184
- }
185
- }
164
+ pub fn get_kv_list_by_namespace ( & self , namespace : & CheetahString ) -> Option < Vec < u8 > > {
165
+ let config_table = self . config_table . read ( ) ;
166
+ config_table. get ( namespace) . map ( |kv_table| {
167
+ let table = KVTable {
168
+ table : kv_table. clone ( ) ,
169
+ } ;
170
+ table. encode ( )
171
+ } )
186
172
}
187
173
188
174
// Gets the value for a specific key in a namespace.
189
175
pub fn get_kvconfig (
190
176
& self ,
191
- namespace : impl Into < CheetahString > ,
192
- key : impl Into < CheetahString > ,
177
+ namespace : & CheetahString ,
178
+ key : & CheetahString ,
193
179
) -> Option < CheetahString > {
194
- match self . config_table . get ( namespace. into ( ) . as_str ( ) ) {
180
+ let config_table = self . config_table . read ( ) ;
181
+ match config_table. get ( namespace) {
195
182
None => None ,
196
- Some ( kv_table) => {
197
- if let Some ( value) = kv_table. get ( key. into ( ) . as_str ( ) ) {
198
- return Some ( value. clone ( ) ) ;
199
- }
200
- None
201
- }
183
+ Some ( kv_table) => kv_table. get ( key) . cloned ( ) ,
202
184
}
203
185
}
204
186
}
187
+
188
+ #[ cfg( test) ]
189
+ mod tests {
190
+ use rocketmq_common:: common:: namesrv:: namesrv_config:: NamesrvConfig ;
191
+ use rocketmq_rust:: ArcMut ;
192
+
193
+ use super :: * ;
194
+
195
+ fn create_kv_config_manager ( ) -> KVConfigManager {
196
+ let namesrv_config = ArcMut :: new ( NamesrvConfig :: default ( ) ) ;
197
+ KVConfigManager :: new ( namesrv_config)
198
+ }
199
+
200
+ #[ test]
201
+ fn new_kv_config_manager_initializes_empty_config_table ( ) {
202
+ let manager = create_kv_config_manager ( ) ;
203
+ assert ! ( manager. get_config_table( ) . is_empty( ) ) ;
204
+ }
205
+
206
+ #[ test]
207
+ fn put_kv_config_creates_new_entry ( ) {
208
+ let mut manager = create_kv_config_manager ( ) ;
209
+ manager. put_kv_config ( "namespace" . into ( ) , "key" . into ( ) , "value" . into ( ) ) ;
210
+ let config_table = manager. get_config_table ( ) ;
211
+ assert_eq ! ( config_table[ "namespace" ] [ "key" ] , "value" ) ;
212
+ }
213
+
214
+ #[ test]
215
+ fn put_kv_config_updates_existing_entry ( ) {
216
+ let mut manager = create_kv_config_manager ( ) ;
217
+ manager. put_kv_config ( "namespace" . into ( ) , "key" . into ( ) , "value" . into ( ) ) ;
218
+ manager. put_kv_config ( "namespace" . into ( ) , "key" . into ( ) , "new_value" . into ( ) ) ;
219
+ let config_table = manager. get_config_table ( ) ;
220
+ assert_eq ! ( config_table[ "namespace" ] [ "key" ] , "new_value" ) ;
221
+ }
222
+
223
+ #[ test]
224
+ fn delete_kv_config_removes_entry ( ) {
225
+ let mut manager = create_kv_config_manager ( ) ;
226
+ manager. put_kv_config ( "namespace" . into ( ) , "key" . into ( ) , "value" . into ( ) ) ;
227
+ manager. delete_kv_config ( & "namespace" . into ( ) , & "key" . into ( ) ) ;
228
+ let config_table = manager. get_config_table ( ) ;
229
+ assert ! ( config_table[ "namespace" ] . get( "key" ) . is_none( ) ) ;
230
+ }
231
+
232
+ #[ test]
233
+ fn delete_kv_config_does_nothing_if_key_does_not_exist ( ) {
234
+ let mut manager = create_kv_config_manager ( ) ;
235
+ manager. put_kv_config ( "namespace" . into ( ) , "key" . into ( ) , "value" . into ( ) ) ;
236
+ manager. delete_kv_config ( & "namespace" . into ( ) , & "non_existent_key" . into ( ) ) ;
237
+ let config_table = manager. get_config_table ( ) ;
238
+ assert_eq ! ( config_table[ "namespace" ] [ "key" ] , "value" ) ;
239
+ }
240
+
241
+ #[ test]
242
+ fn get_kv_list_by_namespace_returns_encoded_list ( ) {
243
+ let mut manager = create_kv_config_manager ( ) ;
244
+ manager. put_kv_config ( "namespace" . into ( ) , "key" . into ( ) , "value" . into ( ) ) ;
245
+ let kv_list = manager. get_kv_list_by_namespace ( & "namespace" . into ( ) ) ;
246
+ assert ! ( kv_list. is_some( ) ) ;
247
+ }
248
+
249
+ #[ test]
250
+ fn get_kv_list_by_namespace_returns_none_if_namespace_does_not_exist ( ) {
251
+ let manager = create_kv_config_manager ( ) ;
252
+ let kv_list = manager. get_kv_list_by_namespace ( & "non_existent_namespace" . into ( ) ) ;
253
+ assert ! ( kv_list. is_none( ) ) ;
254
+ }
255
+
256
+ #[ test]
257
+ fn get_kvconfig_returns_value_if_key_exists ( ) {
258
+ let mut manager = create_kv_config_manager ( ) ;
259
+ manager. put_kv_config ( "namespace" . into ( ) , "key" . into ( ) , "value" . into ( ) ) ;
260
+ let value = manager. get_kvconfig ( & "namespace" . into ( ) , & "key" . into ( ) ) ;
261
+ assert_eq ! ( value, Some ( "value" . into( ) ) ) ;
262
+ }
263
+
264
+ #[ test]
265
+ fn get_kvconfig_returns_none_if_key_does_not_exist ( ) {
266
+ let manager = create_kv_config_manager ( ) ;
267
+ let value = manager. get_kvconfig ( & "namespace" . into ( ) , & "non_existent_key" . into ( ) ) ;
268
+ assert ! ( value. is_none( ) ) ;
269
+ }
270
+ }
0 commit comments