diff --git a/CHANGES.txt b/CHANGES.txt index 209a8a3..8cd32ea 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,16 @@ +1.4.0 (2010-09-30) +------------------ + +- Enabled ketama and compression in pylibmc_wrapper. Both options + are better for clusters. + +- Oracle: Use a more optimal query for POSKeyError logging. + +- Fixed a NameError that occurred when getting the history of an + object where transaction extended info was set. + + 1.4.0c4 (2010-09-17) -------------------- diff --git a/buildout-oracle.cfg b/buildout-oracle.cfg index a48d6a4..5ba2811 100644 --- a/buildout-oracle.cfg +++ b/buildout-oracle.cfg @@ -1,19 +1,3 @@ [buildout] extends = buildout.cfg -parts = cx_Oracle ${buildout:base-parts} eggs += cx_Oracle -oracle_home = /usr/lib/oracle/xe/app/oracle/product/10.2.0/server - -[cx_Oracle] -recipe = zc.recipe.egg:custom -environment = oracle-env -rpath = ${buildout:oracle_home}/lib - -[oracle-env] -ORACLE_HOME = ${buildout:oracle_home} - -[test] -environment = oracle-env - -[test-coverage] -environment = oracle-env diff --git a/relstorage/adapters/txncontrol.py b/relstorage/adapters/txncontrol.py index 35985c3..3a821fe 100644 --- a/relstorage/adapters/txncontrol.py +++ b/relstorage/adapters/txncontrol.py @@ -105,14 +105,12 @@ class MySQLTransactionControl(TransactionControl): def get_tid(self, cursor): """Returns the most recent tid.""" - # Lock in share mode to ensure the data being read is up to date. if self.keep_history: stmt = """ SELECT tid FROM transaction ORDER BY tid DESC LIMIT 1 - LOCK IN SHARE MODE """ cursor.execute(stmt) else: @@ -121,7 +119,6 @@ class MySQLTransactionControl(TransactionControl): FROM object_state ORDER BY tid DESC LIMIT 1 - LOCK IN SHARE MODE """ cursor.execute(stmt) if not cursor.rowcount: @@ -210,4 +207,3 @@ class OracleTransactionControl(TransactionControl): cursor.execute(stmt, ( tid, packed and 'Y' or 'N', self.Binary(username), self.Binary(description), self.Binary(extension))) - diff --git a/relstorage/pylibmc_wrapper.py b/relstorage/pylibmc_wrapper.py index b97e814..2b53078 100644 --- a/relstorage/pylibmc_wrapper.py +++ b/relstorage/pylibmc_wrapper.py @@ -22,14 +22,18 @@ from _pylibmc import MemcachedError # pylibmc >= 0.9 class Client(object): + behaviors = { + "tcp_nodelay": True, + "ketama": True, + } def __init__(self, servers): self._client = pylibmc.Client(servers, binary=True) - self._client.set_behaviors({ - "tcp_nodelay": True, - #"no block": True, - #"buffer requests": True, - }) + self._client.set_behaviors(self.behaviors) + if pylibmc.support_compression: + self.min_compress_len = 1000 + else: + self.min_compress_len = 0 def get(self, key): try: @@ -45,19 +49,22 @@ class Client(object): def set(self, key, value): try: - return self._client.set(key, value) + return self._client.set( + key, value, min_compress_len=self.min_compress_len) except MemcachedError: return None def set_multi(self, d): try: - return self._client.set_multi(d) + return self._client.set_multi( + d, min_compress_len=self.min_compress_len) except MemcachedError: return None def add(self, key, value): try: - return self._client.add(key, value) + return self._client.add( + key, value, min_compress_len=self.min_compress_len) except MemcachedError: return None @@ -72,4 +79,3 @@ class Client(object): self._client.flush_all() except MemcachedError: return None - diff --git a/relstorage/storage.py b/relstorage/storage.py index 41b6ec5..fed5894 100644 --- a/relstorage/storage.py +++ b/relstorage/storage.py @@ -29,7 +29,6 @@ from ZODB.UndoLogCompatible import UndoLogCompatible from ZODB.utils import p64 from ZODB.utils import u64 from zope.interface import implements -from zope.interface import Interface import base64 import cPickle import logging @@ -399,18 +398,14 @@ class RelStorage( msg = ["POSKeyError on oid %d: %s" % (oid_int, reason)] if adapter.keep_history: - rows = adapter.dbiter.iter_transactions(cursor) - row = None - for row in rows: - # just get the first row - break - if not row: + tid = adapter.txncontrol.get_tid(cursor) + if not tid: # This happens when initializing a new database or # after packing, so it's not a warning. logfunc = log.debug msg.append("No previous transactions exist") else: - msg.append("Current transaction is %d" % row[0]) + msg.append("Current transaction is %d" % tid) tids = [] try: @@ -980,7 +975,7 @@ class RelStorage( for tid_int, username, description, extension, length in rows: tid = p64(tid_int) if extension: - d = loads(extension) + d = cPickle.loads(extension) else: d = {} d.update({"time": TimeStamp(tid).timeTime(), diff --git a/relstorage/tests/reltestbase.py b/relstorage/tests/reltestbase.py index 3166c89..40b3579 100644 --- a/relstorage/tests/reltestbase.py +++ b/relstorage/tests/reltestbase.py @@ -459,6 +459,25 @@ class GenericRelStorageTests( finally: db.close() + def checkHistoryWithExtension(self): + # Verify the history method works with transactions that have + # extended info. + db = DB(self._storage) + try: + conn = db.open() + try: + conn.root()['pi'] = 3.14 + transaction.get().setExtendedInfo("digits", 3) + transaction.commit() + history = self._storage.history(conn.root()._p_oid) + self.assertEqual(len(history), 1) + if self.keep_history: + self.assertEqual(history[0]['digits'], 3) + finally: + conn.close() + finally: + db.close() + def checkPackDutyCycle(self): # Exercise the code in the pack algorithm that releases the # commit lock for a time to allow concurrent transactions to commit. diff --git a/setup.py b/setup.py index ff3b11e..f94a902 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ ############################################################################## """A backend for ZODB that stores pickles in a relational database.""" -VERSION = "1.4.0c4" +VERSION = "1.4.0" # The choices for the Trove Development Status line: # Development Status :: 5 - Production/Stable @@ -21,7 +21,7 @@ VERSION = "1.4.0c4" # Development Status :: 3 - Alpha classifiers = """\ -Development Status :: 4 - Beta +Development Status :: 5 - Production/Stable Intended Audience :: Developers License :: OSI Approved :: Zope Public License Programming Language :: Python