import os
import time
import transaction
from ZODB import Connection
from ZODB.DB import DB
from ZODB.FileStorage.FileStorage import FileStorage, read_index


def main():
    db = DB(FileStorage('Data.fs'))

    transaction.begin()
    conn = db.open()
    conn.root()['msg'] = 'Hello!'
    transaction.commit()
    conn.close()
    print conn

    pid = os.fork()
    if pid:
        # Old process
        for i in range(2):
            time.sleep(0.25)
            result = os.waitpid(pid, os.WNOHANG)
            if result[0]:
                break
        if not result[0]:
            os.kill(pid, 9)
            print 'process hung'
        else:
            # 1. Simply try to get the data from the database.
            #    Result: Original Entry.
            conn = db.open()
            print 'Original Process: ' + conn.root()['msg']
            conn.close()
            print conn

            # 2. Create a custom connection to ensure that the connection
            #    cache is not used.
            #    Result: Original Entry.
            conn2 = Connection.Connection(db)
            conn2.open()
            print 'Original Process (new conn): ' + conn2.root()['msg']

            # 3. Invalidate database cache.
            #    Result: Original Entry.
            db.invalidateCache()
            conn = db.open()
            print 'Original Process (cache invalidated): ' + conn.root()['msg']

            # 4. Reload the index.
            #    Result: New Entry!
            # It seems that the data is written to the file, but the index is
            # not updated. That makes sense, since the forked process
            # maintains its own memory table.
            st = db._storage
            (index, vindex, tindex, tvindex,
             oid2tid, toid2tid, toid2tid_delete) = st._newIndexes()

            index, vindex, start, ltid = st._restore_index()
            st._initIndex(index, vindex, tindex, tvindex,
                          oid2tid, toid2tid, toid2tid_delete)
            st._pos, st._oid, tid = read_index(
                st._file, st._file_name, index, vindex, tindex, '\377'*8,
                ltid=ltid, start=start, read_only=False,
                )
            conn = db.open()
            print 'Original Process (index reloaded): ' + conn.root()['msg']

            # Okay, so reloading the index worked; unfortunately, for large
            # databases this can take a relatively long time (i.e. minutes).

            # 5. Close database and reload data file.
            #    Result: New Entry!
            # Let's close the file storage file handle. This is needed so that
            # the lock is released.
            db.close()
            # Create the DB file storage from scratch.  Note that the
            # controlling process usually does not have to do that.  The
            # reason we have to do this is to get a new file handle.
            db = DB(FileStorage('Data.fs'))
            conn = db.open()
            print 'Original Process (DB reloaded): ' + conn.root()['msg']
            conn.close()
            print conn
    else:
        # New Process
        transaction.begin()
        conn = db.open()
        print 'Forked Process: ' + conn.root()['msg']
        conn.root()['msg'] = 'Hello World!'
        transaction.commit()
        conn.close()
        print conn
        db._storage._save_index()


if __name__ == '__main__':
    main()
