Hello,

My NSDocument based app uses packages with the following structure:

- document.package
+- metadata.plist (small, mutable)
+- large0.file (large, immutable)
+- large1.file (large, immutable)
+- large2.file (large, immutable)

While the metadata.plist file can change any time, all large files are created 
once and then stay as they are.
As my "large0-2" files can be several gigabytes, I try to carefully avoid 
unnecessary IO by using document packages with NSFileWrapper.
My package reading/writing methods resemble the ones in the "Document Package 
with iCloud" sample (But I don't use iCloud): 
http://developer.apple.com/library/mac/#samplecode/PackagedDocument/ 
I appended the relevant parts of my code at the end of this message.

With this setup, I was hoping that the occasions where the document 
architecture has to copy the whole bundle are reduced to:
- File duplication
- Moves to another volume

But after investigating file activity with Instruments.app, it turned out that 
my app is reading and writing chunks of my unmodified, immutable & large files 
during each save.
It seems that the copying is related to document revisions (a.k.a. Versions).
Instruments logs hundreds of IO operations in the form of:
#       Caller  Function        FD      Path    Bytes
...
70      copyfile        read    22      document.package/large0.file    1048576
71      copyfile        write   23      
/.vol/16777218/2/.DocumentRevisions-V100/staging/adding.Wohcjo4i/4772FAAA-78D3-44A9-9412-A2D651B6EB5A.package/large0.file
       1048576
70      copyfile        read    22      document.package/large0.file    1048576
71      copyfile        write   23      
/.vol/16777218/2/.DocumentRevisions-V100/staging/adding.Wohcjo4i/4772FAAA-78D3-44A9-9412-A2D651B6EB5A.package/large0.file
       1048576
70      copyfile        read    22      document.package/large0.file    1048576
71      copyfile        write   23      
/.vol/16777218/2/.DocumentRevisions-V100/staging/adding.Wohcjo4i/4772FAAA-78D3-44A9-9412-A2D651B6EB5A.package/large0.file
       1048576
...

How can I tell Versions that the only file that constantly changes within my 
document.package is metadata.info? (Without turning off document revisions 
altogether)
I am targetting 10.8 (with sandboxing enabled) and also adopted async saving 
and autosavesInPlace.

with kind regards,
Thomas

---

- (NSFileWrapper*)fileWrapperOfType:(NSString*)typeName 
error:(NSError**)outError
{
    if([self documentFileWrapper] == nil)
    {
        NSFileWrapper* documentFileWrapper = [[NSFileWrapper alloc] 
initDirectoryWithFileWrappers:nil];
        [self setDocumentFileWrapper:documentFileWrapper];
        [documentFileWrapper release];
    }
    NSURL* documentURL = [self fileURL] == nil ? [self 
autosavedContentsFileURL] : [self fileURL];
    if(documentURL)
    {
        //Check if we already have a metadata file wrapper. If "YES" remove it.
        NSFileWrapper* previousRecordingInfoFileWrapper = [[[self 
documentFileWrapper] fileWrappers] objectForKey:kSSWInfoPlistFilename];
        if(previousRecordingInfoFileWrapper != nil)
        {
            [[self documentFileWrapper] 
removeFileWrapper:previousRecordingInfoFileWrapper];
        }
        NSData* recordingInfoData = [NSPropertyListSerialization 
dataFromPropertyList:recordingInfoDict format:NSPropertyListXMLFormat_v1_0 
errorDescription:&serializationErrorDescriptions];
        [self unblockUserInteraction];
        NSFileWrapper* recordingInfoFileWrapper = [[NSFileWrapper alloc] 
initRegularFileWithContents:recordingInfoData];
        [recordingInfoFileWrapper setPreferredFilename:kSSWInfoPlistFilename];
        [[self documentFileWrapper] addFileWrapper:recordingInfoFileWrapper];
        [recordingInfoFileWrapper release];
        if(([[[self documentFileWrapper] fileWrappers] 
objectForKey:kSSWRecordingFrameName] == nil))
        {
            NSFileWrapper* frameFileWrapper = [[NSFileWrapper alloc] 
initWithURL:[documentURL URLByAppendingPathComponent:kSSWRecordingFrameName] 
options:0 error:outError];
            [frameFileWrapper setPreferredFilename:kSSWRecordingFrameName];
            [[self documentFileWrapper] addFileWrapper:frameFileWrapper];
            [frameFileWrapper release];
        }
                ...
        }
}

- (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString 
*)typeName error:(NSError **)outError
{
    BOOL didRead = NO;
    NSFileWrapper* recordingInfoWrapper = [[fileWrapper fileWrappers] 
objectForKey:kSSWInfoPlistFilename];
    if(!recordingInfoWrapper)
    {
        NSMutableDictionary* errorDetail = [NSMutableDictionary dictionary];
        NSString* errorDescription = NSLocalizedString(@"Could not open 
recording.\nThe recording is missing it's metadata file.", @"Displayed when 
trying to open a corrupted bundle");
        [errorDetail setValue:errorDescription 
forKey:NSLocalizedDescriptionKey];
        if(outError)
        {
            *outError = [NSError errorWithDomain:kSSWRecordingErrorDomain 
code:100 userInfo:errorDetail];
        }
    }
    else
    {
        NSDictionary* recordingInfoDict = [NSPropertyListSerialization 
propertyListWithData:[recordingInfoWrapper regularFileContents] options:0 
format:nil error:outError];
        if(recordingInfoDict)
        {
                        self.recordingInfo = recordingInfoDict;
        }
    }
    [self setDocumentFileWrapper:fileWrapper];
    return didRead;
}


_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to