Author: dmeyer
Date: Thu Jun 28 20:15:10 2007
New Revision: 2747

Added:
   trunk/WIP/beacon2/src/server/db.py
      - copied, changed from r2746, /trunk/WIP/beacon2/src/db.py
Modified:
   trunk/WIP/beacon2/src/db.py
   trunk/WIP/beacon2/src/server/server.py

Log:
start splitting client and server db

Modified: trunk/WIP/beacon2/src/db.py
==============================================================================
--- trunk/WIP/beacon2/src/db.py (original)
+++ trunk/WIP/beacon2/src/db.py Thu Jun 28 20:15:10 2007
@@ -87,39 +87,6 @@
             'changed': kaa.notifier.Signal()
             }
 
-        if self.client:
-            # client mode, nothing more to do
-            return
-
-        # server lock when a client is doing something
-        self.read_lock = False
-        
-        # register basic types
-        self._db.register_object_type_attrs("dir",
-            # This multi-column index optimizes queries on (name,parent) which
-            # is done for every object add/update, so must be fast.  All
-            # object types will have this combined index.
-            [("name", "parent_type", "parent_id")],
-            name = (str, ATTR_KEYWORDS),
-            overlay = (bool, ATTR_SIMPLE),
-            media = (int, ATTR_INDEXED),
-            mtime = (int, ATTR_SIMPLE))
-
-        self._db.register_object_type_attrs("file",
-            [("name", "parent_type", "parent_id")],
-            name = (str, ATTR_KEYWORDS),
-            overlay = (bool, ATTR_SIMPLE),
-            media = (int, ATTR_INDEXED),
-            mtime = (int, ATTR_SIMPLE))
-
-        self._db.register_object_type_attrs("media",
-            [("name", "parent_type", "parent_id")],
-            name = (str, ATTR_KEYWORDS),
-            content = (str, ATTR_SIMPLE))
-
-        # commit
-        self._db.commit()
-
 
     # -------------------------------------------------------------------------
     # Query functions
@@ -437,7 +404,7 @@
                 result.append(create_item(r, parent))
 
             counter += 1
-            if self.client and not counter % 50 and time.time() > timer + 0.05:
+            if not counter % 50 and time.time() > timer + 0.05:
                 # we are in async mode and already use too much time.
                 # call yield YieldContinue at this point to continue
                 # later.
@@ -457,110 +424,6 @@
     # (Except get_db_info which is only for debugging)
     # -------------------------------------------------------------------------
 
-    def commit(self):
-        """
-        Commit changes to the database. All changes in the internal list
-        are done first.
-        """
-        if self.client:
-            raise RuntimeError('unable to commit for a client')
-        
-        # db commit
-        t1 = time.time()
-        self._db.commit()
-        t2 = time.time()
-
-        # some time debugging
-        log.info('db.commit %d items; kaa.db commit %.5f' % \
-                 (len(changes), t2-t1)
-        changes = self.changes
-        self.changes = []
-
-        # fire db changed signal
-        self.signals['changed'].emit(changes)
-
-
-    def add_object(self, type, metadata=None, **kwargs):
-        """
-        Add an object to the db.
-        """
-        if self.read_lock:
-            raise IOError('database is locked')
-
-        if metadata:
-            for key in self._db._object_types[type][1].keys():
-                if metadata.has_key(key) and metadata[key] != None and \
-                       not key in kwargs:
-                    kwargs[key] = metadata[key]
-
-        result = self._db.add_object(type, **kwargs)
-        self.changes.append((result['type'], result['id']))
-        if len(self.changes) > MAX_BUFFER_CHANGES:
-            self.commit()
-        return result
-
-
-    def update_object(self, (type, id), metadata=None, **kwargs):
-        """
-        Update an object to the db.
-        """
-        if self.read_lock:
-            raise IOError('database is locked')
-        
-        if metadata:
-            for key in self._db._object_types[type][1].keys():
-                if metadata.has_key(key) and metadata[key] != None and \
-                       not key == 'media':
-                    kwargs[key] = metadata[key]
-
-        if 'media' in kwargs:
-            del kwargs['media']
-        self._db.update_object((type, id), **kwargs)
-        self.changes.append((type, id))
-        if len(self.changes) > MAX_BUFFER_CHANGES:
-            self.commit()
-
-
-    def update_object_type(self, (type, id), new_type):
-        if self.read_lock:
-            raise IOError('database is locked')
-
-        old_entry = self._db.query(type=type, id=id)
-        if not old_entry:
-            # already changed by something
-            return None
-        # FIXME: crashes with new ObjectRows code
-        old_entry = dict(old_entry[0])
-
-        # copy metadata to new object
-        metadata = {}
-        for key in self._db._object_types[new_type][1].keys():
-            if not key == 'id' and key in old_entry:
-                metadata[key] = old_entry[key]
-
-        metadata = self._db.add_object(new_type, **metadata)
-        new_beacon_id = (type, metadata['id'])
-
-        # move all children to new parent
-        for child in self._db.query(parent=(type, id)):
-            log.warning('untested code: mode parent for %s' % child)
-            id = (child['type'], child['id'])
-            self._db.update_object(id, parent=new_beacon_id)
-
-        # delete old and sync the db again
-        self.delete_object((type, id))
-        return metadata
-
-
-    def delete_object(self, item_or_type_id_list):
-        if self.read_lock:
-            raise IOError('database is locked')
-        for id in self._delete(item_or_type_id_list):
-            self.changes.append(id)
-        if len(self.changes) > MAX_BUFFER_CHANGES:
-            self.commit()
-
-
     def object_types(self):
         """
         Return the list of object types
@@ -568,23 +431,6 @@
         return self._db._object_types
 
 
-    def register_object_type_attrs(self, type, *args, **kwargs):
-        """
-        Register a new object with attributes. Special keywords like name and
-        mtime are added by default.
-        """
-        kwargs['name'] = (str, ATTR_KEYWORDS)
-        # TODO: mtime may not e needed for subitems like tracks
-        kwargs['overlay'] = (bool, ATTR_SIMPLE)
-        kwargs['media'] = (int, ATTR_INDEXED)
-        if not type.startswith('track_'):
-            kwargs['mtime'] = (int, ATTR_SIMPLE)
-            kwargs['image'] = (str, ATTR_SIMPLE)
-        indices = [("name", "parent_type", "parent_id")]
-        return self._db.register_object_type_attrs(type, indices, *args,
-                                                   **kwargs)
-
-
     def get_db_info(self):
         """
         Returns information about the database.  Look at
@@ -593,17 +439,6 @@
         return self._db.get_db_info()
 
 
-    def delete_media(self, id):
-        """
-        Delete media with the given id.
-        """
-        log.info('delete media %s', id)
-        for child in self._db.query(media = id):
-            self._db.delete_object((str(child['type']), child['id']))
-        self._db.delete_object(('media', id))
-        self._db.commit()
-
-
     # -------------------------------------------------------------------------
     # Internal functions
     # -------------------------------------------------------------------------
@@ -636,25 +471,7 @@
             current = self._db.add_object("dir", name=name,
                                           parent=parent._beacon_id,
                                           media=media._beacon_id[1])
-            self._db.commit()
+            self.commit()
         else:
             current = current[0]
         return create_file(current, parent, isdir=True)
-
-
-    def _delete(self, entry):
-        """
-        Delete item with the given id from the db and all items with that
-        items as parent (and so on). To avoid internal problems, make sure
-        commit is called just after this function is called.
-        """
-        log.info('delete %s', entry)
-        if isinstance(entry, Item):
-            entry = entry._beacon_id
-        deleted = [ entry ]
-        for child in self._db.query(parent = entry):
-            deleted.extend(self._delete((child['type'], child['id'])))
-
-        # FIXME: if the item has a thumbnail, delete it!
-        self._db.delete_object(entry)
-        return deleted

Copied: trunk/WIP/beacon2/src/server/db.py (from r2746, 
/trunk/WIP/beacon2/src/db.py)
==============================================================================
--- /trunk/WIP/beacon2/src/db.py        (original)
+++ trunk/WIP/beacon2/src/server/db.py  Thu Jun 28 20:15:10 2007
@@ -44,8 +44,9 @@
 from kaa.db import *
 
 # beacon imports
-from item import Item
-from media import medialist
+from kaa.beacon.item import Item
+from kaa.beacon.media import medialist
+from kaa.beacon.db import Database as RO_Database
 
 # get logging object
 log = logging.getLogger('beacon.db')
@@ -53,43 +54,20 @@
 MAX_BUFFER_CHANGES = 30
 
 # Item generation mapping
-from file import File as create_file
-from item import create_item
+from kaa.beacon.file import File as create_file
+from kaa.beacon.item import create_item
 
 
-class Database(object):
+class Database(RO_Database):
     """
     A kaa.db based database.
     """
 
-    def __init__(self, dbdir, client):
+    def __init__(self, dbdir):
         """
         Init function
         """
-        # internal db dir, it contains the real db and the
-        # overlay dir for the beacon
-        self.dbdir = dbdir
-
-        # remember client
-        # no client == server == write access
-        self.client = client
-
-        # handle changes in a list and add them to the database
-        # on commit.
-        self.changes = []
-
-        # create db
-        if not os.path.isdir(self.dbdir):
-            os.makedirs(self.dbdir)
-        self._db = db.Database(self.dbdir + '/db')
-
-        self.signals = {
-            'changed': kaa.notifier.Signal()
-            }
-
-        if self.client:
-            # client mode, nothing more to do
-            return
+        super(Database,self).__init__(dbdir, None)
 
         # server lock when a client is doing something
         self.read_lock = False
@@ -122,335 +100,6 @@
 
 
     # -------------------------------------------------------------------------
-    # Query functions
-    #
-    # The query functions can modify the database when in server mode. E.g.
-    # a directory query could detect deleted files and will delete them in
-    # the database. In client mode, the query functions will use the database
-    # read only.
-    # -------------------------------------------------------------------------
-
-    def query(self, **query):
-        """
-        Main query function. This function will call one of the specific
-        query functions ins this class depending on the query. This function
-        may raise an AsyncProcess exception.
-        """
-        qlen = len(query)
-        if not 'media' in query:
-            # query only media we have right now
-            query['media'] = db.QExpr('in', medialist.idlist)
-        else:
-            if query['media'] == 'ignore':
-                del query['media']
-            qlen -= 1
-
-        # do query based on type
-        if 'filename' in query and qlen == 1:
-            fname = os.path.realpath(query['filename'])
-            return self._db_query_filename(fname)
-        if 'id' in query and qlen == 1:
-            return self._db_query_id(query['id'])
-        if 'parent' in query and 'recursive' in query and qlen == 2:
-            if not query['parent']._beacon_isdir:
-                raise AttributeError('parent is no directory')
-            return self._db_query_dir_recursive(query['parent'])
-        if 'parent' in query:
-            if qlen == 1:
-                if query['parent']._beacon_isdir:
-                    return self._db_query_dir(query['parent'])
-            query['parent'] = query['parent']._beacon_id
-        if 'attr' in query:
-            return self._db_query_attr(query)
-        if 'type' in query and query['type'] == 'media':
-            return self._db.query(**query)
-        return self._db_query_raw(query)
-
-
-    def query_media(self, id, media):
-        """
-        Get media and the root filesystem. If 'media' is None,
-        the root filesystem is also None. You have to pass a media
-        object to get media and root filesystem.
-        Returns dbinfo, beacon_id, root
-        """
-        result = self._db.query(type="media", name=id)
-        if not result:
-            return None, None, None
-        result = result[0]
-        id = ('media', result['id'])
-        if not media:
-            return result, id, None
-        # TODO: it's a bit ugly to set url here, but we have no other choice
-        media.url = result['content'] + '://' + media.mountpoint
-        root = self._db.query(parent=id)[0]
-        if root['type'] == 'dir':
-            return result, id, create_file(root, media, isdir=True)
-        return result, id, create_item(root, media)
-
-
-    @kaa.notifier.yield_execution()
-    def _db_query_dir(self, parent):
-        """
-        A query to get all files in a directory. The parameter parent is a
-        directort object.
-        """
-        if parent._beacon_islink:
-            # WARNING: parent is a link, we need to follow it
-            dirname = os.path.realpath(parent.filename)
-            parent = self._db_query_filename(dirname)
-            if not parent._beacon_isdir:
-                # oops, this is not directory anymore, return nothing
-                yield []
-        else:
-            dirname = parent.filename[:-1]
-
-        listing = parent._beacon_listdir(async=True)
-
-        if isinstance(listing, kaa.notifier.InProgress):
-            # oops, something takes more time than we had in mind,
-            yield listing
-            # when we reach this point, we can continue
-            listing = listing()
-
-        items = []
-        if parent._beacon_id:
-            items = [ create_file(i, parent, isdir=i['type'] == 'dir') \
-                      for i in self._db.query(parent = parent._beacon_id) ]
-
-        # sort items based on name. The listdir is also sorted by name,
-        # that makes checking much faster
-        items.sort(lambda x,y: cmp(x._beacon_name, y._beacon_name))
-
-        # TODO: use parent mtime to check if an update is needed. Maybe call
-        # it scan time or something like that. Also make it an option so the
-        # user can turn the feature off.
-
-        pos = -1
-
-        # FIXME: ACTIVE WAITING:
-        while self.read_lock:
-            yield kaa.notifier.YieldContinue
-
-        for pos, (f, fullname, overlay, stat_res) in enumerate(listing[0]):
-            isdir = stat.S_ISDIR(stat_res[stat.ST_MODE])
-            if pos == len(items):
-                # new file at the end
-                if isdir:
-                    if not overlay:
-                        items.append(create_file(f, parent, isdir=True))
-                    continue
-                items.append(create_file(f, parent, overlay, isdir=False))
-                continue
-            while pos < len(items) and f > items[pos]._beacon_name:
-                # file deleted
-                i = items[pos]
-                items.remove(i)
-                if not self.client:
-                    # no client == server == write access
-                    # delete from database by adding it to the internal changes
-                    # list. It will be deleted right before the next commit.
-                    self.delete_object(i)
-            if pos < len(items) and f == items[pos]._beacon_name:
-                # same file
-                continue
-            # new file
-            if isdir:
-                if not overlay:
-                    items.insert(pos, create_file(f, parent, isdir=True))
-                continue
-            items.insert(pos, create_file(f, parent, overlay, isdir=False))
-
-        if pos + 1 < len(items):
-            # deleted files at the end
-            if not self.client:
-                # no client == server == write access
-                for i in items[pos+1-len(items):]:
-                    self.delete_object(i)
-            items = items[:pos+1-len(items)]
-
-        # no need to sort the items again, they are already sorted based
-        # on name, let us keep it that way. And name is unique in a directory.
-        # items.sort(lambda x,y: cmp(x.url, y.url))
-        yield items
-
-
-    @kaa.notifier.yield_execution()
-    def _db_query_dir_recursive(self, parent):
-        """
-        Return all files in the directory 'parent' including files in
-        subdirectories (and so on). The directories itself will not be
-        returned. If a subdir is a softlink, it will be skipped. This
-        query does not check if the files are still there and if the
-        database list is up to date.
-        """
-        if parent._beacon_islink:
-            # WARNING: parent is a link, we need to follow it
-            dirname = os.path.realpath(parent.filename)
-            parent = self._db_query_filename(dirname)
-            if not parent._beacon_isdir:
-                # oops, this is not directory anymore, return nothing
-                yield []
-        else:
-            dirname = parent.filename[:-1]
-
-        timer = time.time()
-
-        items = []
-        # A list of all directories we will look at. If a link is in the
-        # directory it will be ignored.
-        directories = [ parent ]
-        while directories:
-            parent = directories.pop(0)
-            if not parent._beacon_id:
-                continue
-            for i in self._db.query(parent = parent._beacon_id):
-                if i['type'] == 'dir':
-                    child = create_file(i, parent, isdir=True)
-                    if not child._beacon_islink:
-                        directories.append(child)
-                else:
-                    items.append(create_file(i, parent, isdir=False))
-            if time.time() > timer + 0.1:
-                # we are in async mode and already use too much time.
-                # call yield YieldContinue at this point to continue
-                # later.
-                timer = time.time()
-                yield kaa.notifier.YieldContinue
-
-        # sort items based on name. The listdir is also sorted by name,
-        # that makes checking much faster
-        items.sort(lambda x,y: cmp(x._beacon_name, y._beacon_name))
-        yield items
-
-
-    def _db_query_filename(self, filename):
-        """
-        Return item for filename, can't be in overlay
-        """
-        dirname = os.path.dirname(filename)
-        basename = os.path.basename(filename)
-        m = medialist.mountpoint(filename)
-        if not m:
-            raise AttributeError('mountpoint not found')
-
-        if (os.path.isdir(filename) and m != medialist.mountpoint(dirname)) \
-           or filename == '/':
-            # the filename is the mountpoint itself
-            e = self._db.query(parent=m._beacon_id, name='')
-            return create_file(e[0], m, isdir=True)
-        parent = self._get_dir(dirname, m)
-        if parent._beacon_id:
-            # parent is a valid db item, query
-            e = self._db.query(parent=parent._beacon_id, name=basename)
-            if e:
-                # entry is in the db
-                return create_file(e[0], parent, isdir=e[0]['type'] == 'dir')
-        return create_file(basename, parent, isdir=os.path.isdir(filename))
-
-
-    def _db_query_id(self, (type, id), cache=None):
-        """
-        Return item based on (type,id). Use given cache if provided.
-        """
-        i = self._db.query(type=type, id=id)[0]
-        # now we need a parent
-        if i['name'] == '':
-            # root node found, find correct mountpoint
-            m = medialist.beacon_id(i['parent'])
-            if not m:
-                raise AttributeError('bad media %s' % str(i['parent']))
-            return create_file(i, m, isdir=True)
-
-        # query for parent
-        pid = i['parent']
-        if cache is not None and pid in cache:
-            parent = cache[pid]
-        else:
-            parent = self._db_query_id(pid)
-            if cache is not None:
-                cache[pid] = parent
-
-        if i['type'] == 'dir':
-            # it is a directory, make a dir item
-            return create_file(i, parent, isdir=True)
-        if parent._beacon_isdir:
-            # parent is dir, this item is not
-            return create_file(i, parent)
-        # neither dir nor file, something else
-        return create_item(i, parent)
-
-
-    def _db_query_attr(self, query):
-        """
-        A query to get a list of possible values of one attribute. Special
-        keyword 'attr' the query is used for that. This query will not return
-        a list of items.
-        """
-        attr = query['attr']
-        del query['attr']
-
-        result = self._db.query(attrs=[attr], distinct=True, **query)
-        result = [ x[attr] for x in result if x[attr] ]
-
-        # sort results and return
-        result.sort()
-        return result
-
-
-    @kaa.notifier.yield_execution()
-    def _db_query_raw(self, query):
-        """
-        Do a 'raw' query. This means to query the database and create
-        a list of items from the result. The items will have a complete
-        parent structure. For files / directories this function won't check
-        if they are still there.
-        """
-        result = []
-        cache = {}
-        counter = 0
-        timer = time.time()
-
-        for media in medialist:
-            cache[media._beacon_id] = media
-            cache[media.root._beacon_id] = media.root
-
-        for r in self._db.query(**query):
-
-            # get parent
-            pid = r['parent']
-            if pid in cache:
-                parent = cache[pid]
-            else:
-                parent = self._db_query_id(pid, cache)
-                cache[pid] = parent
-
-            # create item
-            if r['type'] == 'dir':
-                # it is a directory, make a dir item
-                result.append(create_file(r, parent, isdir=True))
-            elif parent._beacon_isdir:
-                # parent is dir, this item is not
-                result.append(create_file(r, parent))
-            else:
-                # neither dir nor file, something else
-                result.append(create_item(r, parent))
-
-            counter += 1
-            if self.client and not counter % 50 and time.time() > timer + 0.05:
-                # we are in async mode and already use too much time.
-                # call yield YieldContinue at this point to continue
-                # later.
-                timer = time.time()
-                yield kaa.notifier.YieldContinue
-
-        if not 'keywords' in query:
-            # sort results by url (name is not unique) and return
-            result.sort(lambda x,y: cmp(x.url, y.url))
-        yield result
-
-
-    # -------------------------------------------------------------------------
     # Database access
     #
     # The database functions are only called for the server.
@@ -462,9 +111,6 @@
         Commit changes to the database. All changes in the internal list
         are done first.
         """
-        if self.client:
-            raise RuntimeError('unable to commit for a client')
-        
         # db commit
         t1 = time.time()
         self._db.commit()
@@ -552,22 +198,6 @@
         return metadata
 
 
-    def delete_object(self, item_or_type_id_list):
-        if self.read_lock:
-            raise IOError('database is locked')
-        for id in self._delete(item_or_type_id_list):
-            self.changes.append(id)
-        if len(self.changes) > MAX_BUFFER_CHANGES:
-            self.commit()
-
-
-    def object_types(self):
-        """
-        Return the list of object types
-        """
-        return self._db._object_types
-
-
     def register_object_type_attrs(self, type, *args, **kwargs):
         """
         Register a new object with attributes. Special keywords like name and
@@ -581,16 +211,16 @@
             kwargs['mtime'] = (int, ATTR_SIMPLE)
             kwargs['image'] = (str, ATTR_SIMPLE)
         indices = [("name", "parent_type", "parent_id")]
-        return self._db.register_object_type_attrs(type, indices, *args,
-                                                   **kwargs)
+        return self._db.register_object_type_attrs(type, indices, *args, 
**kwargs)
 
 
-    def get_db_info(self):
-        """
-        Returns information about the database.  Look at
-        kaa.db.Database.get_db_info() for more details.
-        """
-        return self._db.get_db_info()
+    def delete_object(self, item_or_type_id_list):
+        if self.read_lock:
+            raise IOError('database is locked')
+        for id in self._delete(item_or_type_id_list):
+            self.changes.append(id)
+        if len(self.changes) > MAX_BUFFER_CHANGES:
+            self.commit()
 
 
     def delete_media(self, id):
@@ -608,39 +238,6 @@
     # Internal functions
     # -------------------------------------------------------------------------
 
-    def _get_dir(self, dirname, media):
-        """
-        Get database entry for the given directory. Called recursive to
-        find the current entry. Do not cache results, they could change.
-        """
-        if dirname == media.mountpoint or dirname +'/' == media.mountpoint:
-            # we know that '/' is in the db
-            c = self._db.query(type="dir", name='', parent=media._beacon_id)[0]
-            return create_file(c, media, isdir=True)
-
-        if dirname == '/':
-            raise RuntimeError('media %s not found' % media)
-
-        parent = self._get_dir(os.path.dirname(dirname), media)
-        name = os.path.basename(dirname)
-
-        if not parent._beacon_id:
-            return create_file(name, parent, isdir=True)
-
-        current = self._db.query(type="dir", name=name,
-                                 parent=parent._beacon_id)
-        if not current and self.client:
-            return create_file(name, parent, isdir=True)
-
-        if not current:
-            current = self._db.add_object("dir", name=name,
-                                          parent=parent._beacon_id,
-                                          media=media._beacon_id[1])
-            self._db.commit()
-        else:
-            current = current[0]
-        return create_file(current, parent, isdir=True)
-
 
     def _delete(self, entry):
         """

Modified: trunk/WIP/beacon2/src/server/server.py
==============================================================================
--- trunk/WIP/beacon2/src/server/server.py      (original)
+++ trunk/WIP/beacon2/src/server/server.py      Thu Jun 28 20:15:10 2007
@@ -41,12 +41,12 @@
 from kaa.notifier import OneShotTimer, Timer, Callback
 
 # kaa.beacon imports
-from kaa.beacon.db import *
 from kaa.beacon.media import medialist
 
 # kaa.beacon server imports
 import parser
 import hwmon
+from db import *
 from monitor import Monitor
 from crawl import Crawler
 from config import config

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog

Reply via email to