Library loading defered

This commit is contained in:
Balazs Perlaki-Horvath 2024-09-07 22:22:37 +02:00
parent c9043bfa99
commit 99c99d7785
8 changed files with 127 additions and 22 deletions

View File

@ -216,12 +216,18 @@ struct RootView: View {
}.task {
switch AppType.current {
case .kiwix:
let perfLib = Performance()
LibraryOperations.reopen {
navigation.currentItem = .reading
perfLib.measure("LibraryOperations.reopen")
}
let perf = Performance()
LibraryOperations.scanDirectory(URL.documentDirectory)
perf.measure("scanDirectory")
LibraryOperations.applyFileBackupSetting()
perf.measure("applyFileBackupSetting")
DownloadService.shared.restartHeartbeatIfNeeded()
perf.measure("restartHeartbeatIfNeeded")
case let .custom(zimFileURL):
LibraryOperations.open(url: zimFileURL) {
ZimMigration.forCustomApps()

View File

@ -0,0 +1,36 @@
// This file is part of Kiwix for iOS & macOS.
//
// Kiwix is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// any later version.
//
// Kiwix is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kiwix; If not, see https://www.gnu.org/licenses/.
import Foundation
import QuartzCore
final class Performance {
private let id: UUID
private var start: CFTimeInterval
init(id: UUID = UUID()) {
self.id = id
start = CACurrentMediaTime()
}
func measure(_ msg: String) {
print("\(msg) \(id): \((CACurrentMediaTime() - start) * 1000) ms")
}
func reset() {
start = CACurrentMediaTime()
}
}

View File

@ -0,0 +1,54 @@
// This file is part of Kiwix for iOS & macOS.
//
// Kiwix is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// any later version.
//
// Kiwix is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kiwix; If not, see https://www.gnu.org/licenses/.
#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>
@interface PerformanceObjC : NSObject
@property (nonatomic, strong, readonly) NSUUID *id;
@property (nonatomic, assign) CFTimeInterval start;
- (instancetype)initWithId:(NSUUID *)id;
- (void)measure:(NSString *)msg;
- (void)reset;
@end
@implementation PerformanceObjC
- (instancetype)init {
return [self initWithId:[NSUUID UUID]];
}
- (instancetype)initWithId:(NSUUID *)id {
self = [super init];
if (self) {
_id = id;
_start = CACurrentMediaTime();
}
return self;
}
- (void)measure:(NSString *)msg {
CFTimeInterval elapsedTime = (CACurrentMediaTime() - _start) * 1000;
NSLog(@"%@ %@: %.2f ms", msg, _id.UUIDString, elapsedTime);
}
- (void)reset {
_start = CACurrentMediaTime();
}
@end

View File

@ -26,7 +26,8 @@
#pragma mark - Reader Management
- (void)open:(NSURL *_Nonnull)url NS_REFINED_FOR_SWIFT;
//- (void)open:(NSURL *_Nonnull)url NS_REFINED_FOR_SWIFT;
- (void)store:(NSURL *_Nonnull)url with: (NSUUID *_Nonnull)zimFileID NS_REFINED_FOR_SWIFT;
- (void)close:(NSUUID *_Nonnull)zimFileID NS_REFINED_FOR_SWIFT;
- (NSArray *_Nonnull)getReaderIdentifiers NS_REFINED_FOR_SWIFT;
- (nonnull void *) getArchives;

View File

@ -14,7 +14,7 @@
// along with Kiwix; If not, see https://www.gnu.org/licenses/.
#include <unordered_map>
#import <QuartzCore/QuartzCore.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdocumentation"
#include "kiwix/book.h"
@ -27,6 +27,7 @@
#import "ZimFileService.h"
#import "ZimFileMetaData.h"
#import "PerformanceObjC.h"
@interface ZimFileService ()
@ -68,26 +69,13 @@
#pragma mark - Reader Management
- (void)open:(NSURL *)url {
- (void)store:(NSURL *)url with:(NSUUID *)zimFileID {
try {
// if url does not ends with "zim", skip it
NSString *pathExtension = [[url pathExtension] lowercaseString];
if (![pathExtension isEqualToString:@"zim"]) {
return;
}
// if we have previously added this url, skip it
if ([[self.fileURLs allKeysForObject:url] count] > 0) {
return;
}
// add the archive
[url startAccessingSecurityScopedResource];
zim::Archive archive = zim::Archive([url fileSystemRepresentation]);
self.archives->insert(std::make_pair(std::string(archive.getUuid()), archive));
// store file URL
NSUUID *zimFileID = [[NSUUID alloc] initWithUUIDBytes:(unsigned char *)archive.getUuid().data];
self.fileURLs[zimFileID] = url;
} catch (std::exception) {
NSLog(@"Error opening zim file.");
@ -230,6 +218,18 @@
}
- (zim::Archive *_Nullable) archiveBy: (NSUUID *_Nonnull) zimFileID {
zim::Archive *found = [self findArchiveBy:zimFileID];
if(found == nil) {
NSURL *url = self.fileURLs[zimFileID];
if (url == nil) {
return nil;
}
[self insertIntoArchives:url with:zimFileID];
}
return [self findArchiveBy: zimFileID];
}
- (zim::Archive *_Nullable) findArchiveBy: (NSUUID *_Nonnull) zimFileID {
std::string zimFileID_C = [self zimfileID_C: zimFileID];
auto found = self.archives->find(zimFileID_C);
if (found == self.archives->end()) {
@ -238,6 +238,16 @@
return &(found->second);
}
- (void) insertIntoArchives: (NSURL *_Nonnull) url with: (NSUUID *_Nonnull) zimFileID {
try {
[url startAccessingSecurityScopedResource];
zim::Archive archive = zim::Archive([url fileSystemRepresentation]); // takes the longest time
self.archives->insert(std::make_pair(std::string(archive.getUuid()), archive));
} catch (std::exception) {
NSLog(@"cannot insert archive with: %@, %@", url.absoluteString, zimFileID.UUIDString);
}
}
- (zim::Item) itemIn: (NSUUID *)zimFileID contentPath:(NSString *)contentPath {
if ([contentPath hasPrefix:@"/"]) {
contentPath = [contentPath substringFromIndex:1];

View File

@ -27,7 +27,7 @@ extension ZimFileService {
/// - Parameter bookmark: url bookmark data of the zim file to open
/// - Returns: new url bookmark data if the one used to open the zim file is stale
@discardableResult
func open(fileURLBookmark data: Data) throws -> Data? {
func open(fileURLBookmark data: Data, for uuid: UUID) throws -> Data? {
// resolve url
var isStale: Bool = false
#if os(macOS)
@ -41,8 +41,7 @@ extension ZimFileService {
throw ZimFileOpenError.missing
}
#endif
__open(url)
__store(url, with: uuid)
return isStale ? ZimFileService.getFileURLBookmarkData(for: url) : nil
}

View File

@ -35,7 +35,7 @@ struct LibraryOperations {
// open the file
do {
try ZimFileService.shared.open(fileURLBookmark: fileURLBookmark)
try ZimFileService.shared.open(fileURLBookmark: fileURLBookmark, for: metadata.fileID)
} catch {
return nil
}
@ -73,7 +73,7 @@ struct LibraryOperations {
zimFiles.forEach { zimFile in
guard let data = zimFile.fileURLBookmark else { return }
do {
if let data = try ZimFileService.shared.open(fileURLBookmark: data) {
if let data = try ZimFileService.shared.open(fileURLBookmark: data, for: zimFile.fileID) {
zimFile.fileURLBookmark = data
}
zimFile.isMissing = false

View File

@ -76,7 +76,6 @@ final class LibraryViewModel: ObservableObject {
@MainActor
func start(isUserInitiated: Bool) async {
guard process.state != .inProgress else { return }
let oldState = process.state
do {
// decide if refresh should proceed
let lastRefresh: Date? = Defaults[.libraryLastRefresh]