Author: dmeyer
Date: Thu Sep 13 15:05:30 2007
New Revision: 2805
Log:
Work around a bug (?) in sqlite. The old idea was to send a lock request
to the server and do the query on the client without waiting for the
return. If the db has a write lock it will be gone very soon. But sqlite
on client side does not poll very often which resulted in the query
blocking for up to 2 seconds. Now the code waits on client side for the
rpc db.lock return until it tries the query. This means we always wait
for the rpc roundtrip even when the db is not locked but it makes sure
the queries are fast even if the db server is filling the db.
Modified:
trunk/beacon/src/client.py
trunk/beacon/src/media.py
trunk/beacon/src/query.py
Modified: trunk/beacon/src/client.py
==============================================================================
--- trunk/beacon/src/client.py (original)
+++ trunk/beacon/src/client.py Thu Sep 13 15:05:30 2007
@@ -296,21 +296,22 @@
return True
+ @kaa.notifier.yield_execution()
def _beacon_query(self, **kwargs):
"""
Do a query from the db.
"""
- self.rpc('db.lock')
+ # we have to wait until we are sure that the db is free for
+ # read access or the sqlite client will find a lock and waits
+ # some time until it tries again. That time is too long, it
+ # can take up to two seconds.
+ yield self.rpc('db.lock')
result = self._db.query(**kwargs)
if isinstance(result, kaa.notifier.InProgress):
- cb = kaa.notifier.Callback(self.rpc, 'db.unlock')
- # Call args will be the result set of the query. We don't want to
- # send this over RPC.
- cb.set_ignore_caller_args()
- result.connect(cb)
- else:
- self.rpc('db.unlock')
- return result
+ yield result
+ result = result.get_result()
+ self.rpc('db.unlock')
+ yield result
def _beacon_update(self, item):
@@ -344,15 +345,20 @@
self.rpc('item.update', items)
+ @kaa.notifier.yield_execution()
def _beacon_media_information(self, media):
"""
Get some basic media information.
(similar function in server)
"""
- self.rpc('db.lock')
+ # we have to wait until we are sure that the db is free for
+ # read access or the sqlite client will find a lock and waits
+ # some time until it tries again. That time is too long, it
+ # can take up to two seconds.
+ yield self.rpc('db.lock')
result = self._db.query_media(media)
self.rpc('db.unlock')
- return result
+ yield result
def _beacon_db_information(self):
@@ -367,6 +373,7 @@
# -------------------------------------------------------------------------
@kaa.rpc.expose('connect')
+ @kaa.notifier.yield_execution()
def _connected(self, id, database, media):
"""
Callback to pass the database information to the client.
@@ -379,7 +386,12 @@
new_media = []
medialist.connect(self)
for id, prop in media:
- new_media.append(medialist.add(id, prop))
+ # in the client medialist.add has to lock the db
+ # and needs the db.lock rpc which will always result
+ # in returning an InProgress object.
+ async = medialist.add(id, prop)
+ yield async
+ new_media.append(async.get_result())
self.signals['connect'].emit()
# reconnect query monitors
for query in self._queries[:]:
@@ -424,10 +436,14 @@
Notification that the media with the given id changed.
"""
if medialist.get_by_media_id(id):
+ # Update can take a while but it should not matter here.
+ # The InProgress object can be ignored
medialist.get_by_media_id(id).update(prop)
return
- media = medialist.add(id, prop)
- self.signals['media.add'].emit(media)
+ # Adding a media always returns an InProgress object. Attach
+ # sending the signal to the InProgress return.
+ async = medialist.add(id, prop)
+ async.connect_once(self.signals['media.add'].emit, media)
@kaa.rpc.expose('device.removed')
Modified: trunk/beacon/src/media.py
==============================================================================
--- trunk/beacon/src/media.py (original)
+++ trunk/beacon/src/media.py Thu Sep 13 15:05:30 2007
@@ -36,6 +36,7 @@
import logging
# kaa imports
+import kaa.notifier
from kaa.weakref import weakref
# kaa.beacon imports
@@ -49,19 +50,13 @@
# check what mounpoint needs right now
- def __init__(self, id, controller, prop):
+ def __init__(self, id, controller):
+ log.info('new media %s', id)
self._controller = controller
self.id = id
- self.update(prop)
-
# needed by server.
self.crawler = None
- log.info('new media %s', self.id)
-
- # when we are here the media is in the database and also
- # the item for it
-
def get_controller(self):
"""
@@ -77,6 +72,7 @@
self._controller.eject(self)
+ @kaa.notifier.yield_execution()
def update(self, prop):
"""
Update media properties.
@@ -91,6 +87,11 @@
self._beacon_media = weakref(self)
# get basic information from database
media = self._controller._beacon_media_information(self)
+ if isinstance(media, kaa.notifier.InProgress):
+ # This will happen for the client because in the client
+ # _beacon_media_information needs to lock the db.
+ yield media
+ media = media.get_result()
prop['beacon.content'] = media['content']
self._beacon_isdir = False
if media['content'] == 'file':
@@ -145,6 +146,7 @@
self._controller = controller
+ @kaa.notifier.yield_execution()
def add(self, id, prop):
"""
Add a media.
@@ -152,11 +154,16 @@
if not self._controller:
raise RuntimeError('not connected to database')
if id in self._dict:
- return self._dict.get(id)
- media = Media(id, self._controller, prop)
+ yield self._dict.get(id)
+ media = Media(id, self._controller)
+ async = media.update(prop)
+ if isinstance(async, kaa.notifier.InProgress):
+ # This will happen for the client because update
+ # needs to lock the db.
+ yield async
self._dict[id] = media
self._idlist = [ m._beacon_id[1] for m in self._dict.values() ]
- return media
+ yield media
def remove(self, id):
Modified: trunk/beacon/src/query.py
==============================================================================
--- trunk/beacon/src/query.py (original)
+++ trunk/beacon/src/query.py Thu Sep 13 15:05:30 2007
@@ -181,13 +181,12 @@
return
self.result = self._client._beacon_query(**query)
-
- if isinstance(self.result, kaa.notifier.InProgress):
- yield self.result
- self.result = self.result()
- # Since query was async, we need to emit 'changed' signal, so
- # override emit_signal argument.
- emit_signal = True
+ # _beacon_query always is async because it call a rpc
+ yield self.result
+ self.result = self.result()
+ # Since query was async, we need to emit 'changed' signal, so
+ # override emit_signal argument.
+ emit_signal = True
self.valid = True
if emit_signal:
@@ -222,9 +221,9 @@
Changed message from server.
"""
result = self._client._beacon_query(**self._query)
- if isinstance(result, kaa.notifier.InProgress):
- yield result
- result = result.get_result()
+ # _beacon_query always is async because it call a rpc
+ yield result
+ result = result.get_result()
if send_signal or len(self.result) != len(result):
# The query result length is different
self.result = result
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog