1- use std:: collections:: BTreeMap ;
1+ use std:: collections:: { BTreeMap , BTreeSet } ;
22
33use rocket:: async_trait;
44use tokio:: sync:: RwLock ;
@@ -24,6 +24,18 @@ pub trait MetadataService: Send + Sync {
2424 /// refresh if the metadata has changed.
2525 async fn set ( & self , metadata : BTreeMap < String , String > ) -> Result < ( ) , Error > ;
2626
27+ /// Insert or update the given metadata key-value pairs.
28+ ///
29+ /// Existing keys not present in `metadata` are left untouched. Will trigger a
30+ /// registration refresh if the metadata has changed.
31+ async fn upsert ( & self , metadata : BTreeMap < String , String > ) -> Result < ( ) , Error > ;
32+
33+ /// Delete the given metadata keys.
34+ ///
35+ /// Keys that do not exist are ignored. Will trigger a registration refresh if the
36+ /// metadata has changed.
37+ async fn delete ( & self , keys : BTreeSet < String > ) -> Result < ( ) , Error > ;
38+
2739 /// Get all user-set metadata key-value pairs.
2840 async fn get ( & self ) -> Result < BTreeMap < String , String > , Error > ;
2941}
@@ -67,19 +79,16 @@ impl<A: App> OasisMetadataService<A> {
6779 limits,
6880 } )
6981 }
70- }
7182
72- #[ async_trait]
73- impl < A : App > MetadataService for OasisMetadataService < A > {
74- async fn set ( & self , metadata : BTreeMap < String , String > ) -> Result < ( ) , Error > {
75- // Validate metadata against runtime limits.
83+ /// Validate the given metadata map against the configured runtime limits.
84+ fn validate ( & self , metadata : & BTreeMap < String , String > ) -> Result < ( ) , Error > {
7685 let max_user_pairs =
7786 ( self . limits . max_pairs as usize ) . saturating_sub ( RESERVED_METADATA_SLOTS ) ;
7887 if metadata. len ( ) > max_user_pairs {
7988 return Err ( Error :: InvalidArgument ) ;
8089 }
8190
82- for ( key, value) in & metadata {
91+ for ( key, value) in metadata {
8392 // Account for namespace prefix when checking key size.
8493 let full_key_size = METADATA_NAMESPACE . len ( ) + 1 + key. len ( ) ;
8594 if full_key_size > self . limits . max_key_size as usize {
@@ -90,10 +99,63 @@ impl<A: App> MetadataService for OasisMetadataService<A> {
9099 }
91100 }
92101
102+ Ok ( ( ) )
103+ }
104+ }
105+
106+ #[ async_trait]
107+ impl < A : App > MetadataService for OasisMetadataService < A > {
108+ async fn set ( & self , metadata : BTreeMap < String , String > ) -> Result < ( ) , Error > {
109+ self . validate ( & metadata) ?;
110+
93111 let mut map = self . metadata . write ( ) . await ;
112+ if * map == metadata {
113+ return Ok ( ( ) ) ;
114+ }
94115 * map = metadata;
95116
96- // Refresh registration.
117+ self . env . refresh_registration ( ) . await ?;
118+
119+ Ok ( ( ) )
120+ }
121+
122+ async fn upsert ( & self , metadata : BTreeMap < String , String > ) -> Result < ( ) , Error > {
123+ let mut map = self . metadata . write ( ) . await ;
124+
125+ let mut updated = map. clone ( ) ;
126+ let mut changed = false ;
127+ for ( key, value) in metadata {
128+ if updated. get ( & key) != Some ( & value) {
129+ updated. insert ( key, value) ;
130+ changed = true ;
131+ }
132+ }
133+ self . validate ( & updated) ?;
134+
135+ if !changed {
136+ return Ok ( ( ) ) ;
137+ }
138+ * map = updated;
139+
140+ self . env . refresh_registration ( ) . await ?;
141+
142+ Ok ( ( ) )
143+ }
144+
145+ async fn delete ( & self , keys : BTreeSet < String > ) -> Result < ( ) , Error > {
146+ let mut map = self . metadata . write ( ) . await ;
147+
148+ let mut changed = false ;
149+ for key in & keys {
150+ if map. remove ( key) . is_some ( ) {
151+ changed = true ;
152+ }
153+ }
154+
155+ if !changed {
156+ return Ok ( ( ) ) ;
157+ }
158+
97159 self . env . refresh_registration ( ) . await ?;
98160
99161 Ok ( ( ) )
0 commit comments