Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature/mem-optimizations] Optimize memory usage #121

Merged
merged 6 commits into from
Jan 23, 2025
4 changes: 2 additions & 2 deletions ownCloudSDK/Bookmark/OCBookmark+DataItem.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#import "OCDataTypes.h"
#import "OCResource.h"
#import "OCMacros.h"
#import "OCCoreManager.h"
#import "OCPlatform.h"

@implementation OCBookmark (DataItem)

Expand All @@ -36,7 +36,7 @@ - (OCDataItemReference)dataItemReference

- (OCDataItemVersion)dataItemVersion
{
if (OCCoreManager.sharedCoreManager.memoryConfiguration != OCCoreMemoryConfigurationMinimum)
if (OCPlatform.current.memoryConfiguration != OCPlatformMemoryConfigurationMinimum)
{
OCResource *avatarResource = OCTypedCast(self.avatar, OCResource);
NSString *avatarVersion = ((avatarResource != nil) ? avatarResource.version : @"");
Expand Down
5 changes: 5 additions & 0 deletions ownCloudSDK/Bookmark/OCBookmark.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ NS_ASSUME_NONNULL_BEGIN
- (void)removeCapability:(OCBookmarkCapability)capability;
- (BOOL)hasCapability:(OCBookmarkCapability)capability;

#pragma mark - Metadata storage
@property(strong,nullable) NSURL *metaDataStorageURL; //!< URL to store bookmark data in (f.ex. certificates, avatar images, ..)

- (nullable NSError *)storeMetadata;

#pragma mark - Certificate approval
- (NSNotificationName)certificateUserApprovalUpdateNotificationName; //!< Notification that gets sent if the bookmark's certificate user-approved status changed
- (void)postCertificateUserApprovalUpdateNotification; //!< Posts a .certificateUserApprovalUpdateNotificationName notification
Expand Down
74 changes: 69 additions & 5 deletions ownCloudSDK/Bookmark/OCBookmark.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ @interface OCBookmark ()
OCIPCNotificationName _bookmarkAuthUpdateNotificationName;

id<OCViewProvider> _avatar;
NSURL *_avatarDataURL;
NSData *_avatarData;

NSString *_lastUsername;
Expand Down Expand Up @@ -246,19 +247,64 @@ - (OCCertificate *)primaryCertificate
return (primaryCertificate);
}

#pragma mark - Metadata storage
- (NSError *)storeMetadata
{
NSError *error = nil;

@synchronized(self)
{
if (_metaDataStorageURL != nil)
{
if ([NSFileManager.defaultManager createDirectoryAtURL:_metaDataStorageURL withIntermediateDirectories:YES attributes:nil error:&error])
{
if ((_avatarDataURL != nil) && (_avatarData != nil))
{
[_avatarData writeToURL:_avatarDataURL options:NSDataWritingAtomic error:&error];
}
}
}
}

return (error);
}

#pragma mark - Avatar
- (NSData *)avatarData
{
@synchronized(self)
{
if ((_avatarData == nil) && (_avatarDataURL != nil))
{
_avatarData = [[NSData alloc] initWithContentsOfURL:_avatarDataURL];
}
}

return (_avatarData);
}

- (id<OCViewProvider>)avatar
{
@synchronized(self)
{
if ((_avatar == nil) && (_avatarData != nil))
if (_avatar == nil)
{
@try
NSData *avatarData = _avatarData;

if ((avatarData == nil) && (_avatarDataURL != nil))
{
_avatar = [NSKeyedUnarchiver unarchiveObjectWithData:_avatarData];
avatarData = [[NSData alloc] initWithContentsOfURL:_avatarDataURL];
}
@catch (NSException *exception)

if (avatarData != nil)
{
@try
{
_avatar = [NSKeyedUnarchiver unarchiveObjectWithData:avatarData];
}
@catch (NSException *exception)
{
}
}
}

Expand Down Expand Up @@ -304,6 +350,15 @@ - (void)setAvatar:(id<OCViewProvider>)avatar

_avatar = (avatarData != nil) ? avatar : nil;
_avatarData = avatarData;

if ((avatarData != nil) && (_metaDataStorageURL != nil))
{
_avatarDataURL = [_metaDataStorageURL URLByAppendingPathComponent:@"avatarData"];
}
else
{
_avatarDataURL = nil;
}
}
}

Expand Down Expand Up @@ -415,6 +470,8 @@ - (instancetype)initWithCoder:(NSCoder *)decoder

_originURL = [decoder decodeObjectOfClass:NSURL.class forKey:@"originURL"];

_metaDataStorageURL = [decoder decodeObjectOfClass:NSURL.class forKey:@"metaDataStorageURL"];

_capabilities = [decoder decodeObjectOfClasses:[NSSet setWithObjects:NSSet.class, NSString.class, nil] forKey:@"capabilities"];

_certificateStore = [decoder decodeObjectOfClass:OCCertificateStore.class forKey:@"certificateStore"];
Expand All @@ -435,6 +492,7 @@ - (instancetype)initWithCoder:(NSCoder *)decoder
_authenticationValidationDate = [decoder decodeObjectOfClass:NSDate.class forKey:@"authenticationValidationDate"];

_avatarData = [decoder decodeObjectOfClass:NSData.class forKey:@"avatarData"];
_avatarDataURL = [decoder decodeObjectOfClass:NSURL.class forKey:@"avatarDataURL"];

_databaseVersion = [decoder decodeIntegerForKey:@"databaseVersion"];

Expand Down Expand Up @@ -462,14 +520,20 @@ - (void)encodeWithCoder:(NSCoder *)coder

[coder encodeObject:_originURL forKey:@"originURL"];

[coder encodeObject:_metaDataStorageURL forKey:@"metaDataStorageURL"];

[coder encodeObject:_capabilities forKey:@"capabilities"];

[coder encodeObject:_certificateStore forKey:@"certificateStore"];

[coder encodeObject:_authenticationMethodIdentifier forKey:@"authenticationMethodIdentifier"];
[coder encodeObject:_authenticationValidationDate forKey:@"authenticationValidationDate"];

[coder encodeObject:_avatarData forKey:@"avatarData"];
if (_avatarDataURL == nil)
{
[coder encodeObject:_avatarData forKey:@"avatarData"];
}
[coder encodeObject:_avatarDataURL forKey:@"avatarDataURL"];
felix-schwarz marked this conversation as resolved.
Show resolved Hide resolved

[coder encodeInteger:_databaseVersion forKey:@"databaseVersion"];

Expand Down
6 changes: 3 additions & 3 deletions ownCloudSDK/Connection/OCConnection+Upload.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#import "OCHTTPResponse+DAVError.h"
#import "NSProgress+OCExtensions.h"
#import "OCCore+SyncEngine.h"
#import "OCCoreManager.h"
#import "OCPlatform.h"

typedef NSString* OCUploadInfoKey;
typedef NSString* OCUploadInfoTask;
Expand Down Expand Up @@ -241,7 +241,7 @@ - (OCProgress *)_tusUploadFileFromURL:(NSURL *)sourceURL withName:(NSString *)fi
{
NSNumber *capabilitiesTusMaxChunkSize;

if (OCCoreManager.sharedCoreManager.memoryConfiguration != OCCoreMemoryConfigurationMinimum)
if (OCPlatform.current.memoryConfiguration != OCPlatformMemoryConfigurationMinimum)
{
// Memory configuration is NOT minimum, so avoid splitting up files into chunks if
// possible, which requires additional memory and could mean going over a tight memory
Expand Down Expand Up @@ -296,7 +296,7 @@ - (OCProgress *)_continueTusJob:(OCTUSJob *)tusJob lastTask:(NSString *)lastTask
return (nil);
}

if (OCCoreManager.sharedCoreManager.memoryConfiguration == OCCoreMemoryConfigurationMinimum)
if (OCPlatform.current.memoryConfiguration == OCPlatformMemoryConfigurationMinimum)
{
// Memory configuration is minimum, so use just Creation instead of Creation-With-Upload
// to avoid splitting up files into chunks if possible, which requires additional memory
Expand Down
4 changes: 2 additions & 2 deletions ownCloudSDK/Core/ItemList/OCCore+ItemList.m
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ - (NSUInteger)parallelItemListTaskCount
{
switch (self.memoryConfiguration)
{
case OCCoreMemoryConfigurationMinimum:
case OCPlatformMemoryConfigurationMinimum:
return (1);
break;

case OCCoreMemoryConfigurationDefault:
case OCPlatformMemoryConfigurationDefault:
default:
return (2);
break;
Expand Down
15 changes: 0 additions & 15 deletions ownCloudSDK/Core/OCCore+ItemUpdates.m
Original file line number Diff line number Diff line change
Expand Up @@ -124,21 +124,6 @@ - (void)performUpdatesForAddedItems:(nullable NSArray<OCItem *> *)addedItems
}];
}

// In parallel: remove thumbnails from in-memory cache for removed items
OCWaitWillStartTask(cacheUpdatesGroup);

dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
for (OCItem *removeItem in removedItems)
{
if (removeItem.fileID != nil)
{
[self->_thumbnailCache removeObjectForKey:removeItem.fileID];
}
}

OCWaitDidFinishTask(cacheUpdatesGroup);
});

// Wait for updates to complete
OCWaitForCompletion(cacheUpdatesGroup);
}
Expand Down
12 changes: 3 additions & 9 deletions ownCloudSDK/Core/OCCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#import "OCDataSourceComposition.h"
#import "OCDataItemPresentable.h"
#import "OCShareRole.h"
#import "OCPlatform.h"

@class OCCore;
@class OCItem;
Expand Down Expand Up @@ -95,12 +96,6 @@ typedef NS_ENUM(NSUInteger, OCCoreConnectionStatusSignalState)
OCCoreConnectionStatusSignalStateForceTrue //!< Signal state is force true (overriding any false states)
} __attribute__((enum_extensibility(closed)));

typedef NS_ENUM(NSUInteger, OCCoreMemoryConfiguration)
{
OCCoreMemoryConfigurationDefault, //!< Default memory configuration
OCCoreMemoryConfigurationMinimum //!< Try using only the minimum amount of memory needed
} __attribute__((enum_extensibility(closed)));

typedef NS_ENUM(NSUInteger,OCCoreAvailableOfflineCoverage)
{
OCCoreAvailableOfflineCoverageNone, //!< Item is not targeted by available offline item policy
Expand Down Expand Up @@ -156,7 +151,7 @@ typedef id<NSObject> OCCoreItemTracking;
OCConnection *_connection;
BOOL _attemptConnect;

OCCoreMemoryConfiguration _memoryConfiguration;
OCPlatformMemoryConfiguration _memoryConfiguration;

NSMutableArray <OCQuery *> *_queries;

Expand Down Expand Up @@ -229,7 +224,6 @@ typedef id<NSObject> OCCoreItemTracking;

OCSignalManager *_signalManager;

OCCache<OCFileID,OCItemThumbnail *> *_thumbnailCache;
NSMutableDictionary <NSString *, NSMutableArray<OCCoreThumbnailRetrieveHandler> *> *_pendingThumbnailRequests;

NSMutableDictionary <OCIPCNotificationName, id> *_remoteSyncEngineTriggerAcknowledgements;
Expand Down Expand Up @@ -310,7 +304,7 @@ typedef id<NSObject> OCCoreItemTracking;
@property(readonly) OCVault *vault; //!< Vault managing storage and database access for this core.
@property(readonly) OCConnection *connection; //!< Connection used by the core to make requests to the server.

@property(assign,nonatomic) OCCoreMemoryConfiguration memoryConfiguration;
@property(assign,nonatomic) OCPlatformMemoryConfiguration memoryConfiguration;

@property(readonly,nonatomic) OCCoreState state;
@property(copy) OCCoreStateChangedHandler stateChangedHandler;
Expand Down
19 changes: 3 additions & 16 deletions ownCloudSDK/Core/OCCore.m
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,6 @@ - (instancetype)initWithBookmark:(OCBookmark *)bookmark

_claimTokensByClaimIdentifier = [NSMapTable strongToWeakObjectsMapTable];

_thumbnailCache = [OCCache new];

_queue = dispatch_queue_create("OCCore work queue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
_connectivityQueue = dispatch_queue_create("OCCore connectivity queue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);

Expand Down Expand Up @@ -410,7 +408,7 @@ - (instancetype)initWithBookmark:(OCBookmark *)bookmark
[self addSignalProvider:_connectingStatusSignalProvider];
[self addSignalProvider:_connectionStatusSignalProvider];

self.memoryConfiguration = OCCoreManager.sharedCoreManager.memoryConfiguration;
self.memoryConfiguration = OCPlatform.current.memoryConfiguration;

[self startIPCObservation];
}
Expand Down Expand Up @@ -755,7 +753,7 @@ - (void)__attemptConnect
}

// If app provider is available and enabled
if (OCCoreManager.sharedCoreManager.memoryConfiguration != OCCoreMemoryConfigurationMinimum) // only load app providers in memory configurations other than minimum
if (self.memoryConfiguration != OCPlatformMemoryConfigurationMinimum) // only load app providers in memory configurations other than minimum
{
OCAppProvider *latestSupportedAppProvider = self.connection.capabilities.latestSupportedAppProvider;

Expand Down Expand Up @@ -1043,22 +1041,11 @@ - (OCMessageQueue *)messageQueue
}

#pragma mark - Memory configuration
- (void)setMemoryConfiguration:(OCCoreMemoryConfiguration)memoryConfiguration
- (void)setMemoryConfiguration:(OCPlatformMemoryConfiguration)memoryConfiguration
{
_memoryConfiguration = memoryConfiguration;

self.vault.resourceManager.memoryConfiguration = memoryConfiguration;

switch (_memoryConfiguration)
{
case OCCoreMemoryConfigurationDefault:
_thumbnailCache.countLimit = OCCacheLimitNone;
break;

case OCCoreMemoryConfigurationMinimum:
_thumbnailCache.countLimit = 1;
break;
}
}

#pragma mark - Inter-Process change notification/handling
Expand Down
2 changes: 1 addition & 1 deletion ownCloudSDK/Core/Resources/Manager/OCResourceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ typedef void(^OCResourceRetrieveCompletionHandler)(NSError * _Nullable error, OC
@property(weak,nullable) id<OCResourceStorage> storage;
@property(weak,nullable) OCCore *core;

@property(assign,nonatomic) OCCoreMemoryConfiguration memoryConfiguration;
@property(assign,nonatomic) OCPlatformMemoryConfiguration memoryConfiguration;

// @property(assign) NSUInteger maximumConcurrentJobs; //!< Maximum number of jobs to work on in parallel. A value of 0 indicates no limit.

Expand Down
11 changes: 7 additions & 4 deletions ownCloudSDK/Core/Resources/Manager/OCResourceManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,21 @@ - (instancetype)initWithStorage:(id<OCResourceStorage>)storage
return (self);
}

- (void)setMemoryConfiguration:(OCCoreMemoryConfiguration)memoryConfiguration
- (void)setMemoryConfiguration:(OCPlatformMemoryConfiguration)memoryConfiguration
{
_memoryConfiguration = memoryConfiguration;

switch (_memoryConfiguration)
{
case OCCoreMemoryConfigurationDefault:
case OCPlatformMemoryConfigurationDefault:
if (_cache == nil) {
_cache = [OCCache new];
}
_cache.countLimit = OCCacheLimitNone;
break;

case OCCoreMemoryConfigurationMinimum:
_cache.countLimit = 1;
case OCPlatformMemoryConfigurationMinimum:
_cache = nil; // Do not perform any caching
break;
}
}
Expand Down
10 changes: 10 additions & 0 deletions ownCloudSDK/Platforms/OCPlatform.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,20 @@
#define OCView NSView
#endif /* TARGET_OS_OSX */

typedef NS_ENUM(NSUInteger, OCPlatformMemoryConfiguration)
{
OCPlatformMemoryConfigurationDefault, //!< Default memory configuration
OCPlatformMemoryConfigurationMinimum //!< Try using only the minimum amount of memory needed
} __attribute__((enum_extensibility(closed)));

NS_ASSUME_NONNULL_BEGIN

@interface OCPlatform : NSObject

@property(readonly,strong,nonatomic,class) OCPlatform *current;

@property(assign) OCPlatformMemoryConfiguration memoryConfiguration;

@end

NS_ASSUME_NONNULL_END
Loading