@@ -254,6 +254,18 @@ BOOL is_asset_alive(NSMapTable<NSString *, ETCoreMLAsset *> *assets_in_use_map,
254
254
255
255
return assets;
256
256
}
257
+
258
+ NSURL * _Nullable move_to_directory (NSURL *url,
259
+ NSURL *directoryURL,
260
+ NSFileManager *fileManager,
261
+ NSError * __autoreleasing *error) {
262
+ NSURL *dstURL = [directoryURL URLByAppendingPathComponent: [NSUUID UUID ].UUIDString];
263
+ if (![fileManager moveItemAtURL: url toURL: dstURL error: error]) {
264
+ return nil ;
265
+ }
266
+ return dstURL;
267
+ }
268
+
257
269
} // namespace
258
270
259
271
@interface ETCoreMLAssetManager () <NSFileManagerDelegate > {
@@ -299,12 +311,20 @@ - (nullable instancetype)initWithDatabase:(const std::shared_ptr<Database>&)data
299
311
if (!managedAssetsDirectoryURL) {
300
312
return nil ;
301
313
}
302
-
314
+
303
315
NSURL *managedTrashDirectoryURL = ::create_directory_if_needed (trashDirectoryURL, @" models" , fileManager, error);
304
316
if (!managedTrashDirectoryURL) {
305
317
return nil ;
306
318
}
307
-
319
+
320
+ // Remove any existing contents in the staging directory by moving them to the trash directory,
321
+ // then recreate a clean staging directory for new use.
322
+ move_to_directory ([assetsDirectoryURL URLByAppendingPathComponent: @" staging" ], managedTrashDirectoryURL, fileManager, nil );
323
+ NSURL *managedStagingDirectoryURL = ::create_directory_if_needed (assetsDirectoryURL, @" staging" , fileManager, error);
324
+ if (!managedStagingDirectoryURL) {
325
+ return nil ;
326
+ }
327
+
308
328
// If directory is empty then purge the stores
309
329
if (::is_directory_empty (managedAssetsDirectoryURL, fileManager, nil )) {
310
330
assetsMetaStore.impl ()->purge (ec);
@@ -315,6 +335,7 @@ - (nullable instancetype)initWithDatabase:(const std::shared_ptr<Database>&)data
315
335
_assetsStore = std::move (assetsStore);
316
336
_assetsMetaStore = std::move (assetsMetaStore);
317
337
_assetsDirectoryURL = managedAssetsDirectoryURL;
338
+ _stagingDirectoryURL = managedStagingDirectoryURL;
318
339
_trashDirectoryURL = managedTrashDirectoryURL;
319
340
_estimatedSizeInBytes = sizeInBytes.value ();
320
341
_maxAssetsSizeInBytes = maxAssetsSizeInBytes;
@@ -349,12 +370,18 @@ - (nullable instancetype)initWithDatabaseURL:(NSURL *)databaseURL
349
370
- (nullable NSURL *)moveURL : (NSURL *)url
350
371
toUniqueURLInDirectory : (NSURL *)directoryURL
351
372
error : (NSError * __autoreleasing *)error {
352
- NSURL *dstURL = [directoryURL URLByAppendingPathComponent: [NSUUID UUID ].UUIDString];
353
- if (![self .fileManager moveItemAtURL: url toURL: dstURL error: error]) {
354
- return nil ;
373
+ return move_to_directory (url, directoryURL, self.fileManager , error);
374
+ }
375
+
376
+ - (void )withTemporaryDirectory : (void (^)(NSURL *directoryURL))block {
377
+ NSURL *dstURL = [self .stagingDirectoryURL URLByAppendingPathComponent: [NSUUID UUID ].UUIDString];
378
+ block (dstURL);
379
+ if (![self .fileManager fileExistsAtPath: dstURL.path]) {
380
+ return ;
355
381
}
356
-
357
- return dstURL;
382
+
383
+ [self moveURL: dstURL toUniqueURLInDirectory: self .trashDirectoryURL error: nil ];
384
+ [self cleanupTrashDirectory ];
358
385
}
359
386
360
387
- (void )cleanupAssetIfNeeded : (ETCoreMLAsset *)asset {
@@ -407,7 +434,7 @@ - (nullable ETCoreMLAsset *)_storeAssetAtURL:(NSURL *)srcURL
407
434
return false ;
408
435
}
409
436
410
- // If an asset exists move it
437
+ // If an asset exists move it,
411
438
[self moveURL: dstURL toUniqueURLInDirectory: self .trashDirectoryURL error: nil ];
412
439
413
440
// Move the asset to assets directory.
@@ -433,16 +460,25 @@ - (nullable ETCoreMLAsset *)_storeAssetAtURL:(NSURL *)srcURL
433
460
}
434
461
435
462
- (void )triggerCompaction {
436
- if (self.estimatedSizeInBytes < self.maxAssetsSizeInBytes ) {
437
- return ;
463
+ if (self.estimatedSizeInBytes >= self.maxAssetsSizeInBytes ) {
464
+ __weak __typeof (self) weakSelf = self;
465
+ dispatch_async (self.syncQueue , ^{
466
+ NSError *localError = nil ;
467
+ if (![weakSelf _compact: self .maxAssetsSizeInBytes error: &localError]) {
468
+ ETCoreMLLogError (localError, " Failed to compact asset store." );
469
+ }
470
+ });
438
471
}
439
-
472
+
473
+ // Always clean the trash directory to ensure a minimal footprint.
474
+ // The `trashQueue` is serialized, so only one cleanup will run at a time.
475
+ [self cleanupTrashDirectory ];
476
+ }
477
+
478
+ - (void )cleanupTrashDirectory {
440
479
__weak __typeof (self) weakSelf = self;
441
- dispatch_async (self.syncQueue , ^{
442
- NSError *localError = nil ;
443
- if (![weakSelf _compact: self .maxAssetsSizeInBytes error: &localError]) {
444
- ETCoreMLLogError (localError, " Failed to compact asset store." );
445
- }
480
+ dispatch_async (self.trashQueue , ^{
481
+ [weakSelf removeFilesInTrashDirectory ];
446
482
});
447
483
}
448
484
@@ -649,13 +685,7 @@ - (NSUInteger)_compact:(NSUInteger)sizeInBytes error:(NSError * __autoreleasing
649
685
identifier);
650
686
}
651
687
}
652
-
653
- // Trigger cleanup.
654
- __weak __typeof (self) weakSelf = self;
655
- dispatch_async (self.trashQueue , ^{
656
- [weakSelf removeFilesInTrashDirectory ];
657
- });
658
-
688
+
659
689
return _estimatedSizeInBytes;
660
690
}
661
691
@@ -664,7 +694,10 @@ - (NSUInteger)compact:(NSUInteger)sizeInBytes error:(NSError * __autoreleasing *
664
694
dispatch_sync (self.syncQueue , ^{
665
695
result = [self _compact: sizeInBytes error: error];
666
696
});
667
-
697
+
698
+ // Always clean the trash directory to ensure a minimal footprint.
699
+ // The `trashQueue` is serialized, so only one cleanup will run at a time.
700
+ [self cleanupTrashDirectory ];
668
701
return result;
669
702
}
670
703
@@ -724,13 +757,7 @@ - (BOOL)_purge:(NSError * __autoreleasing *)error {
724
757
725
758
::set_error_from_error_code (ec, error);
726
759
// Trigger cleanup
727
- if (status) {
728
- __weak __typeof (self) weakSelf = self;
729
- dispatch_async (self.trashQueue , ^{
730
- [weakSelf removeFilesInTrashDirectory ];
731
- });
732
- }
733
-
760
+ [self cleanupTrashDirectory ];
734
761
return static_cast <BOOL >(status);
735
762
}
736
763
0 commit comments