@@ -48,35 +48,25 @@ impl Database {
48
48
. transpose ( )
49
49
}
50
50
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
54
56
. 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
+ }
80
70
}
81
71
82
72
pub fn exist ( & self , path : & FilePath ) -> ApiResult < bool > {
@@ -95,11 +85,11 @@ impl Database {
95
85
let expire = ( expire_time, path) ;
96
86
match self . expires . write ( ) {
97
87
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
+ } ;
103
93
guard. insert ( expire. clone ( ) ) ;
104
94
drop ( guard) ;
105
95
if is_gc_notify {
@@ -113,7 +103,9 @@ impl Database {
113
103
}
114
104
}
115
105
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
+ ) ) ;
117
109
}
118
110
Err ( err) => {
119
111
tracing:: error!( "Compare and swap error: {err}" ) ;
@@ -138,7 +130,7 @@ impl Database {
138
130
guard. remove ( & ( meta. expiration_date , path) ) ;
139
131
}
140
132
Err ( err) => {
141
- tracing:: error!( "Get expires lock unsuccessfully : {err}" ) ;
133
+ tracing:: error!( "Failed to acquire expires lock: {err}" ) ;
142
134
}
143
135
}
144
136
Ok ( Some ( meta) )
@@ -148,21 +140,20 @@ impl Database {
148
140
}
149
141
150
142
pub async fn purge ( & self ) -> ApiResult < Option < Duration > > {
151
- let now = Utc :: now ( ) ;
152
143
match self . expires . write ( ) {
153
144
Ok ( mut guard) => {
154
145
let expires = & mut * guard;
155
146
while let Some ( ( expire_date, path) ) = expires. iter ( ) . next ( ) . cloned ( ) {
156
- if expire_date < now {
147
+ if expire_date < Utc :: now ( ) {
157
148
self . inner . remove ( & IVec :: try_from ( & path) ?) ?;
158
149
expires. remove ( & ( expire_date, path) ) ;
159
150
} else {
160
- return Ok ( Some ( ( expire_date - now) . to_std ( ) ?) ) ;
151
+ return Ok ( Some ( ( expire_date - Utc :: now ( ) ) . to_std ( ) ?) ) ;
161
152
}
162
153
}
163
154
}
164
155
Err ( err) => {
165
- tracing:: error!( "Get expires lock unsuccessfully : {err}" ) ;
156
+ tracing:: error!( "Failed to acquire expires lock: {err}" ) ;
166
157
return Err ( ApiError :: LockError ( err. to_string ( ) ) ) ;
167
158
}
168
159
}
@@ -331,7 +322,7 @@ mod tests {
331
322
332
323
#[ test_context( StateTestContext ) ]
333
324
#[ 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 ) {
335
326
let path: FilePath = Faker . fake ( ) ;
336
327
let meta = MetaDataFile {
337
328
created_at : Utc :: now ( ) ,
@@ -347,34 +338,14 @@ mod tests {
347
338
. store ( path. clone ( ) , meta. clone ( ) )
348
339
. await
349
340
. 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 ;
370
343
ctx
371
344
. state
372
345
. db
373
- . store ( path. clone ( ) , meta. clone ( ) )
374
- . await
346
+ . update ( & path, meta. clone ( ) , updated_meta)
375
347
. 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 ( ) ;
378
349
assert_eq ! ( result. created_at, meta. created_at) ;
379
350
assert_eq ! ( result. expiration_date, meta. expiration_date) ;
380
351
assert_eq ! ( result. secret, meta. secret) ;
0 commit comments