@@ -48,35 +48,25 @@ impl Database {
4848 . transpose ( )
4949 }
5050
51- pub async fn fetch_count ( & self , file_path : & FilePath ) -> ApiResult < Option < MetaDataFile > > {
52- let mut output = None ;
53- self
51+ pub fn update ( & self , file_path : & FilePath , old : MetaDataFile , new : MetaDataFile ) -> ApiResult {
52+ let old = IVec :: try_from ( old) ?;
53+ let new = IVec :: try_from ( new) ?;
54+ let file_path = IVec :: try_from ( file_path) ?;
55+ let result = self
5456 . inner
55- . fetch_and_update ( IVec :: try_from ( file_path) ?, |value| {
56- value
57- . map ( |val| {
58- MetaDataFile :: try_from ( val)
59- . map ( |mut meta| {
60- meta. count_downloads += 1 ;
61- let val = IVec :: try_from ( & meta) ;
62- output = Some ( meta) ;
63- val
64- . map_err ( |err| {
65- tracing:: error!( "Covnert MetaDataFile to IVec unsuccessfully: {err}" ) ;
66- err
67- } )
68- . ok ( )
69- } )
70- . map_err ( |err| {
71- tracing:: error!( "Covnert IVec to MetaDataFile unsuccessfully: {err}" ) ;
72- err
73- } )
74- . ok ( )
75- } )
76- . flatten ( )
77- . flatten ( )
78- } ) ?;
79- Ok ( output)
57+ . compare_and_swap ( & file_path, Some ( old) , Some ( new) ) ?;
58+ match result {
59+ Ok ( _) => Ok ( ( ) ) ,
60+ Err ( err) if err. current . is_some ( ) => Err ( ApiError :: BadRequestError (
61+ "Update meta data failed" . to_string ( ) ,
62+ ) ) ,
63+ Err ( err) => {
64+ tracing:: error!( "Compare and swap error: {err}" ) ;
65+ Err ( ApiError :: DatabaseError ( sled:: Error :: ReportableBug (
66+ "Storing the meta data file in the database faild." . to_string ( ) ,
67+ ) ) )
68+ }
69+ }
8070 }
8171
8272 pub fn exist ( & self , path : & FilePath ) -> ApiResult < bool > {
@@ -95,11 +85,11 @@ impl Database {
9585 let expire = ( expire_time, path) ;
9686 match self . expires . write ( ) {
9787 Ok ( mut guard) => {
98- let is_gc_notify = guard
99- . iter ( )
100- . next ( )
101- . filter ( | ( exp , _ ) | * exp < Utc :: now ( ) )
102- . is_some ( ) ;
88+ let is_gc_notify = if let Some ( ( first_expire , _ ) ) = guard. iter ( ) . next ( ) {
89+ * first_expire > expire_time
90+ } else {
91+ true
92+ } ;
10393 guard. insert ( expire. clone ( ) ) ;
10494 drop ( guard) ;
10595 if is_gc_notify {
@@ -113,7 +103,9 @@ impl Database {
113103 }
114104 }
115105 Err ( err) if err. current . is_some ( ) => {
116- return Err ( ApiError :: ResourceExistsError ( "File path exists" . to_string ( ) ) ) ;
106+ return Err ( ApiError :: ResourceExistsError (
107+ "File path exists" . to_string ( ) ,
108+ ) ) ;
117109 }
118110 Err ( err) => {
119111 tracing:: error!( "Compare and swap error: {err}" ) ;
@@ -138,7 +130,7 @@ impl Database {
138130 guard. remove ( & ( meta. expiration_date , path) ) ;
139131 }
140132 Err ( err) => {
141- tracing:: error!( "Get expires lock unsuccessfully : {err}" ) ;
133+ tracing:: error!( "Failed to acquire expires lock: {err}" ) ;
142134 }
143135 }
144136 Ok ( Some ( meta) )
@@ -148,21 +140,20 @@ impl Database {
148140 }
149141
150142 pub async fn purge ( & self ) -> ApiResult < Option < Duration > > {
151- let now = Utc :: now ( ) ;
152143 match self . expires . write ( ) {
153144 Ok ( mut guard) => {
154145 let expires = & mut * guard;
155146 while let Some ( ( expire_date, path) ) = expires. iter ( ) . next ( ) . cloned ( ) {
156- if expire_date < now {
147+ if expire_date < Utc :: now ( ) {
157148 self . inner . remove ( & IVec :: try_from ( & path) ?) ?;
158149 expires. remove ( & ( expire_date, path) ) ;
159150 } else {
160- return Ok ( Some ( ( expire_date - now) . to_std ( ) ?) ) ;
151+ return Ok ( Some ( ( expire_date - Utc :: now ( ) ) . to_std ( ) ?) ) ;
161152 }
162153 }
163154 }
164155 Err ( err) => {
165- tracing:: error!( "Get expires lock unsuccessfully : {err}" ) ;
156+ tracing:: error!( "Failed to acquire expires lock: {err}" ) ;
166157 return Err ( ApiError :: LockError ( err. to_string ( ) ) ) ;
167158 }
168159 }
@@ -331,7 +322,7 @@ mod tests {
331322
332323 #[ test_context( StateTestContext ) ]
333324 #[ tokio:: test]
334- async fn test_store_file_and_fetch_count ( ctx : & mut StateTestContext ) {
325+ async fn test_store_and_update_file ( ctx : & mut StateTestContext ) {
335326 let path: FilePath = Faker . fake ( ) ;
336327 let meta = MetaDataFile {
337328 created_at : Utc :: now ( ) ,
@@ -347,34 +338,14 @@ mod tests {
347338 . store ( path. clone ( ) , meta. clone ( ) )
348339 . await
349340 . unwrap ( ) ;
350- let result = ctx. state . db . fetch_count ( & path) . await . unwrap ( ) . unwrap ( ) ;
351- assert_eq ! ( result. created_at, meta. created_at) ;
352- assert_eq ! ( result. expiration_date, meta. expiration_date) ;
353- assert_eq ! ( result. secret, meta. secret) ;
354- assert_eq ! ( result. max_download, meta. max_download) ;
355- assert_eq ! ( result. count_downloads, meta. count_downloads) ;
356- }
357-
358- #[ test_context( StateTestContext ) ]
359- #[ tokio:: test]
360- async fn test_store_file_and_double_fetch_count ( ctx : & mut StateTestContext ) {
361- let path: FilePath = Faker . fake ( ) ;
362- let meta = MetaDataFile {
363- created_at : Utc :: now ( ) ,
364- expiration_date : Utc :: now ( ) + chrono:: Duration :: seconds ( 10 ) ,
365- secret : None ,
366- delete_manually : true ,
367- max_download : None ,
368- count_downloads : 0 ,
369- } ;
341+ let mut updated_meta = meta. clone ( ) ;
342+ updated_meta. count_downloads += 1 ;
370343 ctx
371344 . state
372345 . db
373- . store ( path. clone ( ) , meta. clone ( ) )
374- . await
346+ . update ( & path, meta. clone ( ) , updated_meta)
375347 . unwrap ( ) ;
376- ctx. state . db . fetch_count ( & path) . await . unwrap ( ) . unwrap ( ) ;
377- let result = ctx. state . db . fetch_count ( & path) . await . unwrap ( ) . unwrap ( ) ;
348+ let result = ctx. state . db . fetch ( & path) . unwrap ( ) . unwrap ( ) ;
378349 assert_eq ! ( result. created_at, meta. created_at) ;
379350 assert_eq ! ( result. expiration_date, meta. expiration_date) ;
380351 assert_eq ! ( result. secret, meta. secret) ;
0 commit comments