zodb.py 3.44 KB
Newer Older
1
# Wendelin.bigfile | common ZODB-related helpers
2 3 4 5 6 7 8 9
# Copyright (C) 2014-2015  Nexedi SA and Contributors.
#                          Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
10 11 12 13
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
14 15 16 17 18
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
19
# See https://www.nexedi.com/licensing for rationale and options.
20 21 22

from ZODB.FileStorage import FileStorage
from ZODB import DB
23 24
from persistent import Persistent
import gc
25 26


27 28
# open db storage by uri
def dbstoropen(uri):
29 30 31 32 33 34 35 36 37 38 39 40 41
    # if we can - use zodbtools to open via zodburi
    try:
        import zodbtools.util
    except ImportError:
        return _dbstoropen(uri)

    return zodbtools.util.storageFromURL(uri)


# simplified fallback to open a storage by URI when zodbtools/zodburi are not available.
# ( they require ZODB, instead of ZODB3, and thus we cannot use
#   them together with ZODB 3.10 which we still support )
def _dbstoropen(uri):
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
    if uri.startswith('neo://'):
        # XXX hacky, only 1 master supported
        from neo.client.Storage import Storage
        name, master = uri[6:].split('@', 1)    # neo://db@master -> db, master
        stor = Storage(master_nodes=master, name=name)

    elif uri.startswith('zeo://'):
        # XXX hacky
        from ZEO.ClientStorage import ClientStorage
        host, port = uri[6:].split(':',1)       # zeo://host:port -> host, port
        port = int(port)
        stor = ClientStorage((host, port))

    else:
        stor = FileStorage(uri)

    return stor


61
# open stor/db/connection and return root obj
62 63
def dbopen(uri):
    stor = dbstoropen(uri)
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
    db   = DB(stor)
    conn = db.open()
    root = conn.root()
    return root


# close db/connection/storage identified by root obj
def dbclose(root):
    conn = root._p_jar
    db   = conn.db()
    stor = db.storage

    conn.close()
    db.close()
    stor.close()
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107


# deactivate a btree, including all internal buckets and leaf nodes
def deactivate_btree(btree):
    # first activate btree, to make sure its first bucket is loaded at all.
    #
    # we have to do this because btree could be automatically deactivated
    # before by cache (the usual way) and then in its ghost state it does not
    # contain pointer to first bucket and thus we won't be able to start
    # bucket deactivation traversal.
    btree._p_activate()

    for _ in gc.get_referents(btree):
        # for top-level btree we ignore any direct referent besides bucket
        # (there are _p_jar, cache, etc)
        if type(_) is btree._bucket_type:
            _deactivate_bucket(_)

    btree._p_deactivate()

def _deactivate_bucket(bucket):
    # TODO also support objects in keys, when we need it
    for obj in bucket.values():
        if type(obj) == type(bucket):
            _deactivate_bucket(obj)
        elif isinstance(obj, Persistent):
            obj._p_deactivate()

    bucket._p_deactivate()