Defining FileStorages using ZConfig
===================================

ZODB provides support for defining many storages, including
FileStorages, using ZConfig.  To define a FileStorage, you use a
filestorage section, and define a path:

    >>> import ZODB.config
    >>> fs = ZODB.config.storageFromString("""
    ... <filestorage>
    ...     path my.fs
    ... </filestorage>
    ... """)

    >>> fs._file.name
    'my.fs'

    >>> fs.close()

There are a number of options we can provide:

blob-dir
    If supplied, the file storage will provide blob support and this
    is the name of a directory to hold blob data.  The directory will
    be created if it doeesn't exist.  If no value (or an empty value)
    is provided, then no blob support will be provided. (You can still
    use a BlobStorage to provide blob support.)

    >>> fs = ZODB.config.storageFromString("""
    ... <filestorage>
    ...     path my.fs
    ...     blob-dir blobs
    ... </filestorage>
    ... """)

    >>> fs._file.name
    'my.fs'
    >>> import os
    >>> os.path.basename(fs.blob_dir)
    'blobs'

create
    Flag that indicates whether the storage should be truncated if
    it already exists.

    To demonstrate this, we'll first write some data:

    >>> db = ZODB.DB(fs)
    >>> conn = db.open()
    >>> import ZODB.blob, transaction
    >>> conn.root()[1] = ZODB.blob.Blob()
    >>> transaction.commit()
    >>> db.close()

    Then reopen with the create option:

    >>> fs = ZODB.config.storageFromString("""
    ... <filestorage>
    ...     path my.fs
    ...     blob-dir blobs
    ...     create true
    ... </filestorage>
    ... """)

    Because the file was truncated, we no-longer have object 0:

    >>> fs.load(b'\0'*8)
    Traceback (most recent call last):
    ...
    POSKeyError: 0x00

    >>> sorted(os.listdir('blobs'))
    ['.layout', 'tmp']

    >>> fs.close()

read-only
    If true, only reads may be executed against the storage.  Note
    that the "pack" operation is not considered a write operation
    and is still allowed on a read-only filestorage.

    >>> fs = ZODB.config.storageFromString("""
    ... <filestorage>
    ...     path my.fs
    ...     read-only true
    ... </filestorage>
    ... """)
    >>> fs.isReadOnly()
    True
    >>> fs.close()

quota
    Maximum allowed size of the storage file.  Operations which
    would cause the size of the storage to exceed the quota will
    result in a ZODB.FileStorage.FileStorageQuotaError being
    raised.

    >>> fs = ZODB.config.storageFromString("""
    ... <filestorage>
    ...     path my.fs
    ...     quota 10
    ... </filestorage>
    ... """)
    >>> db = ZODB.DB(fs) # writes object 0
    Traceback (most recent call last):
    ...
    FileStorageQuotaError: The storage quota has been exceeded.

    >>> fs.close()

packer
    The dotten name (dotten module name and object name) of a
    packer object.  This is used to provide an alternative pack
    implementation.

    To demonstrate this, we'll create a null packer that just prints
    some information about it's arguments:

    >>> import six
    >>> def packer(storage, referencesf, stop, gc):
    ...     six.print_(referencesf, storage is fs, gc, storage.pack_keep_old)
    >>> ZODB.FileStorage.config_demo_printing_packer = packer

    >>> fs = ZODB.config.storageFromString("""
    ... <filestorage>
    ...     path my.fs
    ...     packer ZODB.FileStorage.config_demo_printing_packer
    ... </filestorage>
    ... """)

    >>> import time
    >>> db = ZODB.DB(fs) # writes object 0
    >>> fs.pack(time.time(), 42)
    42 True True True

    >>> fs.close()

    If the packer contains a ':', then the text after the first ':' is
    interpreted as an expression. This is handy to pass limited
    configuration information to the packer:

    >>> def packer_factory(name):
    ...     def packer(storage, referencesf, stop, gc):
    ...         six.print_(repr(name), referencesf, storage is fs,
    ...                    gc, storage.pack_keep_old)
    ...     return packer
    >>> ZODB.FileStorage.config_demo_printing_packer_factory = packer_factory

    >>> fs = ZODB.config.storageFromString("""
    ... <filestorage>
    ...     path my.fs
    ...     packer ZODB.FileStorage:config_demo_printing_packer_factory('bob ')
    ... </filestorage>
    ... """)

    >>> import time
    >>> db = ZODB.DB(fs) # writes object 0
    >>> fs.pack(time.time(), 42)
    'bob ' 42 True True True

    >>> fs.close()



pack-gc
    If false, then no garbage collection will be performed when
    packing.  This can make packing go much faster and can avoid
    problems when objects are referenced only from other
    databases.

    >>> fs = ZODB.config.storageFromString("""
    ... <filestorage>
    ...     path my.fs
    ...     packer ZODB.FileStorage.config_demo_printing_packer
    ...     pack-gc false
    ... </filestorage>
    ... """)

    >>> fs.pack(time.time(), 42)
    42 True False True

    Note that if we pass the gc option to pack, then this will
    override the value set in the configuration:

    >>> fs.pack(time.time(), 42, gc=True)
    42 True True True
    
    >>> fs.close()

pack-keep-old
    If false, then old files aren't kept when packing

    >>> fs = ZODB.config.storageFromString("""
    ... <filestorage>
    ...     path my.fs
    ...     packer ZODB.FileStorage.config_demo_printing_packer
    ...     pack-keep-old false
    ... </filestorage>
    ... """)

    >>> fs.pack(time.time(), 42)
    42 True True False
    
    >>> fs.close()




    
