16
16
// under the License.
17
17
18
18
//! An in-memory object store implementation
19
+ use crate :: multipart:: { MultiPartStore , PartId } ;
19
20
use crate :: util:: InvalidGetRange ;
20
21
use crate :: {
21
22
path:: Path , GetRange , GetResult , GetResultPayload , ListResult , ObjectMeta , ObjectStore ,
@@ -28,8 +29,8 @@ use chrono::{DateTime, Utc};
28
29
use futures:: { stream:: BoxStream , StreamExt } ;
29
30
use parking_lot:: RwLock ;
30
31
use snafu:: { OptionExt , ResultExt , Snafu } ;
31
- use std:: collections:: BTreeMap ;
32
32
use std:: collections:: BTreeSet ;
33
+ use std:: collections:: { BTreeMap , HashMap } ;
33
34
use std:: io;
34
35
use std:: ops:: Range ;
35
36
use std:: pin:: Pin ;
@@ -52,6 +53,12 @@ enum Error {
52
53
53
54
#[ snafu( display( "ETag required for conditional update" ) ) ]
54
55
MissingETag ,
56
+
57
+ #[ snafu( display( "MultipartUpload not found: {id}" ) ) ]
58
+ UploadNotFound { id : String } ,
59
+
60
+ #[ snafu( display( "Missing part at index: {part}" ) ) ]
61
+ MissingPart { part : usize } ,
55
62
}
56
63
57
64
impl From < Error > for super :: Error {
@@ -101,6 +108,12 @@ impl Entry {
101
108
struct Storage {
102
109
next_etag : usize ,
103
110
map : BTreeMap < Path , Entry > ,
111
+ uploads : HashMap < usize , PartStorage > ,
112
+ }
113
+
114
+ #[ derive( Debug , Default , Clone ) ]
115
+ struct PartStorage {
116
+ parts : Vec < Option < Bytes > > ,
104
117
}
105
118
106
119
type SharedStorage = Arc < RwLock < Storage > > ;
@@ -154,6 +167,24 @@ impl Storage {
154
167
}
155
168
}
156
169
}
170
+
171
+ fn upload_mut ( & mut self , id : & MultipartId ) -> Result < & mut PartStorage > {
172
+ let parts = id
173
+ . parse ( )
174
+ . ok ( )
175
+ . and_then ( |x| self . uploads . get_mut ( & x) )
176
+ . context ( UploadNotFoundSnafu { id } ) ?;
177
+ Ok ( parts)
178
+ }
179
+
180
+ fn remove_upload ( & mut self , id : & MultipartId ) -> Result < PartStorage > {
181
+ let parts = id
182
+ . parse ( )
183
+ . ok ( )
184
+ . and_then ( |x| self . uploads . remove ( & x) )
185
+ . context ( UploadNotFoundSnafu { id } ) ?;
186
+ Ok ( parts)
187
+ }
157
188
}
158
189
159
190
impl std:: fmt:: Display for InMemory {
@@ -359,6 +390,64 @@ impl ObjectStore for InMemory {
359
390
}
360
391
}
361
392
393
+ #[ async_trait]
394
+ impl MultiPartStore for InMemory {
395
+ async fn create_multipart ( & self , _path : & Path ) -> Result < MultipartId > {
396
+ let mut storage = self . storage . write ( ) ;
397
+ let etag = storage. next_etag ;
398
+ storage. next_etag += 1 ;
399
+ storage. uploads . insert ( etag, Default :: default ( ) ) ;
400
+ Ok ( etag. to_string ( ) )
401
+ }
402
+
403
+ async fn put_part (
404
+ & self ,
405
+ _path : & Path ,
406
+ id : & MultipartId ,
407
+ part_idx : usize ,
408
+ data : Bytes ,
409
+ ) -> Result < PartId > {
410
+ let mut storage = self . storage . write ( ) ;
411
+ let upload = storage. upload_mut ( id) ?;
412
+ if part_idx <= upload. parts . len ( ) {
413
+ upload. parts . resize ( part_idx + 1 , None ) ;
414
+ }
415
+ upload. parts [ part_idx] = Some ( data) ;
416
+ Ok ( PartId {
417
+ content_id : Default :: default ( ) ,
418
+ } )
419
+ }
420
+
421
+ async fn complete_multipart (
422
+ & self ,
423
+ path : & Path ,
424
+ id : & MultipartId ,
425
+ _parts : Vec < PartId > ,
426
+ ) -> Result < PutResult > {
427
+ let mut storage = self . storage . write ( ) ;
428
+ let upload = storage. remove_upload ( id) ?;
429
+
430
+ let mut cap = 0 ;
431
+ for ( part, x) in upload. parts . iter ( ) . enumerate ( ) {
432
+ cap += x. as_ref ( ) . context ( MissingPartSnafu { part } ) ?. len ( ) ;
433
+ }
434
+ let mut buf = Vec :: with_capacity ( cap) ;
435
+ for x in & upload. parts {
436
+ buf. extend_from_slice ( x. as_ref ( ) . unwrap ( ) )
437
+ }
438
+ let etag = storage. insert ( path, buf. into ( ) ) ;
439
+ Ok ( PutResult {
440
+ e_tag : Some ( etag. to_string ( ) ) ,
441
+ version : None ,
442
+ } )
443
+ }
444
+
445
+ async fn abort_multipart ( & self , _path : & Path , id : & MultipartId ) -> Result < ( ) > {
446
+ self . storage . write ( ) . remove_upload ( id) ?;
447
+ Ok ( ( ) )
448
+ }
449
+ }
450
+
362
451
impl InMemory {
363
452
/// Create new in-memory storage.
364
453
pub fn new ( ) -> Self {
@@ -444,6 +533,7 @@ mod tests {
444
533
copy_if_not_exists ( & integration) . await ;
445
534
stream_get ( & integration) . await ;
446
535
put_opts ( & integration, true ) . await ;
536
+ multipart ( & integration, & integration) . await ;
447
537
}
448
538
449
539
#[ tokio:: test]
0 commit comments