Prep for 1.4.0:

- 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.
This commit is contained in:
Shane Hathaway 2010-09-30 10:17:16 +00:00
parent d517455956
commit 1b6b36e029
7 changed files with 52 additions and 40 deletions

View File

@ -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)
--------------------

View File

@ -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

View File

@ -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)))

View File

@ -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

View File

@ -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(),

View File

@ -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.

View File

@ -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