< Previous PageNext Page > Hide TOC

Persistent Store Features

Core Data provides several types of persistent store. This article describes the features and benefits of each, and how you can migrate from one type of store to another.

Important: On Mac OS X v10.4, there is no explicit class for persistent stores—you can only type a store instance as an id—consequently there is also no API for persistent store objects. The techniques described below generally also apply to Mac OS X v10.4, but where a type is given as NSPersistentStore * you should use id.

Store Types and Behaviors

Core Data provides three sorts of disk-based persistent store—XML, atomic, and SQLite—and an in-memory store. From the application code perspective, in general you should not be concerned about implementation details for any particular store. You should interact with managed objects and the persistence stack. There are, however, some behavioral differences between the types of store that you should consider when deciding what type of store to use.

XML

Atomic

SQLite

In-Memory

Speed

Slow

Fast

Fast

Fast

Object Graph

Whole

Whole

Partial

Whole

Other Factors

Externally parseable

No backing required

Store-specific behavior

Given the abstraction that Core Data offers, there is no typically need to use the same store throughout the development process. It is common, for example, to use the XML store early in a project life-cycle, since it is fairly human-readable and you can inspect a file to determine whether or not it contains the data you expect. In a deployed application that uses a large data set, you typically use an SQLite store, since this offers high performance and does not require that the entire object graph reside in memory. You might use the binary store if you want store writes to be atomic.

It is important to note, however, that there are some interactions between fetching and the type of store. In the XML, binary, and in-memory stores, evaluation of the predicate and sort descriptors is performed in Objective-C with access to all Cocoa's functionality, including the comparison methods on NSString. The SQL store, on the other hand, compiles the predicate and sort descriptors to SQL and evaluates the result in the database itself. This is done primarily for performance—databases are much faster at this (it's what they're designed for)—but it means that evaluation happens in a non-Cocoa environment, and so sort descriptors (or predicates) that rely on Cocoa cannot work. The supported sort selectors are compare: and caseInsensitiveCompare:. Note that in addition you cannot sort on transient properties using the SQLite store.

File-systems supported by the SQLite store

The SQLite store supports reading data from a file that resides on any type of file-system. The SQLite store does not in general, however, support writing directly to file-systems which do not implement byte-range locking. For DOS filesystems and for some NFS file system implementations that do not support byte-range locking correctly, SQLite will use "<dbfile>.lock" locking, and for SMB file systems it uses flock-style locking.

To summarize: byte-range locking file systems have the best concurrent read/write support; these include HFS+, AFP, and NFS. File systems with simplistic file locking are also supported but do not allow for as much concurrent read/write access by multiple processes; these include SMB, and DOS. The SQLite store does not support writing to WebDAV file-systems (this includes iDisk).

Configuring a SQLite Store’s Save Behavior

When Core Data saves a SQLite store, SQLite updates just part of the store file. Loss of that partial update would be catastrophic, so you may want to ensure that the file is written correctly before your application continues. Unfortunately, doing so means that in some situations saving even a small set of changes to an SQLite store can considerably longer than saving to, say, an XML store. (For example, where saving to an XML file might take less than a hundredth of a second, saving to an SQLite store may take almost half a second. This is not an issue for XML or Binary stores—since they are atomic, there is a much lower likelihood of data loss that involves corruption of the file, especially since the writes are typically atomic and the old file is not deleted until the new has been successfully written.)

fsync on Mac OS X: Since on Mac OS X the fsync command does not make the guarantee that bytes are written, SQLite sends a F_FULLFSYNC request to the kernel to ensures that the bytes are actually written through to the drive platter. This causes the kernel to flush all buffers to the drives and causes the drives to flush their track caches. Without this, there is a significantly large window of time within which data will reside in volatile memory—and in the event of system failure you risk data corruption.

Core Data provides a way to control sync behavior in SQLite using two independent pragmas, giving you control over the tradeoff between performance and reliability:

The pragmas are publicly documented at http://sqlite.org/pragma.html.

You can set both pragmas using the key NSSQLitePragmasOption in the options dictionary when opening the store. The NSSQLitePragmasOption dictionary contains pragma names as keys and string values as objects, as illustrated in the following example:

NSPersistentStoreCoordinator *psc = /* assume this exists */ ;
 
NSMutableDictionary *pragmaOptions = [NSMutableDictionary dictionary];
[pragmaOptions setObject:@"NORMAL" forKey:@"synchronous"];
[pragmaOptions setObject:@"1" forKey:@"fullfsync"];
 
NSDictionary *storeOptions =
    [NSDictionary dictionaryWithObject:pragmaOptions forKey:NSSQLitePragmasOption];
NSPersistentStore *store;
NSError *error;
store = [psc addPersistentStoreWithType:NSSQLiteStoreType
            configuration: nil
            URL:url
            options:storeOptions
            error:&error];

Mac OS X v10.4: Mac OS X v10.4 uses full_fsync by default. Since the fsync command does not make the guarantee that bytes are written, SQLite sends a F_FULLFSYNC request to the kernel. This causes the kernel to flush all buffers to the drives and causes the drives to flush their track caches.

In Mac OS X v10.4, there are only two settings to control the way in which data in a SQLite-based store is written to disk. If you want to trade risk of data corruption against the time taken to save a file, you can set the defaults key com.apple.CoreData.SQLiteDebugSynchronous to one of three values:

0: Disk syncing is switched off

1: Normal

2 (The default): Disk syncing is performed via the fctl FULL_FSYNC command—a costly operation but one that guarantees data is written to disk

Important: Note that the default behaviors on Mac OS X v10.4 an 10.5 are different. On Mac OS X v10.4, SQLite uses FULL_FSYNC by default; on Mac OS X v10.5 it does not.

Custom store types

On Mac OS X v10.5 and later you can create your own atomic store types. For details, see Atomic Store Programming Topics.

On Mac OS X v10.4 , you cannot write your own object store which interoperates transparently with the Core Data stack. You can, however, manage object persistence yourself by using an in-memory store. Before you load your data, you create an in-memory store. When you load your data, you create instances of the appropriate model classes and insert them into a managed object context, associate them with the in-memory store (see insertObject: and assignObject:toPersistentStore:). The managed objects are then fully integrated into the Core Data stack and benefit from features such as undo management. You are also responsible, however, for saving the data. You must register to receive NSManagedObjectContextDidSaveNotification notifications from the managed object context, and upon receipt of the notification save the managed objects to the persistent store.

Security

Core Data makes no guarantees regarding the security of persistent stores from untrusted sources and cannot detect whether files have been maliciously modified. The SQLite store offers slightly better security than the XML and binary stores, but it should not be considered inherently secure. Note that you should also consider the security of store metadata since it is possible for data archived in the metadata to be tampered with independently of the store data. If you want to ensure data security, you should use a technology such as an encrypted disk image.



< Previous PageNext Page > Hide TOC


© 2004, 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-03-04)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.