[Checkins] SVN: gocept.zeoraid/trunk/src/gocept/zeoraid/ - moved
read-only check into decorator
Christian Theune
ct at gocept.com
Wed Jan 16 03:31:27 EST 2008
Log message for revision 82912:
- moved read-only check into decorator
- added test for loadSerial
- refactored tests a bit
Changed:
U gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
U gocept.zeoraid/trunk/src/gocept/zeoraid/tests/failingstorage.py
U gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py
-=-
Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
===================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py 2008-01-16 01:55:53 UTC (rev 82911)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py 2008-01-16 08:31:26 UTC (rev 82912)
@@ -30,6 +30,15 @@
return method(self, *args, **kw)
return check_open
+
+def ensure_writable(method):
+ def check_writable(self, *args, **kw):
+ if self.isReadOnly():
+ raise ZODB.POSException.ReadOnlyError()
+ return method(self, *args, **kw)
+ return check_writable
+
+
no_transaction_marker = object()
def choose_transaction(version, transaction):
@@ -141,6 +150,8 @@
for degraded_storages in tids.values():
self.storages_degraded.extend(degraded_storages)
+ # Degrade storages that don't have the right max OID.
+
# No storages are recovering initially
self.storages_recovering = []
@@ -201,12 +212,14 @@
def loadSerial(self, oid, serial):
"""Load the object record for the give transaction id."""
- return self._apply_single_storage('loadSerial', (oid, serial))
+ return self._apply_single_storage(
+ 'loadSerial', (oid, serial),
+ allowed_exceptions=ZODB.POSException.POSKeyError)
# XXX
+ @ensure_writable
def new_oid(self):
- if self.isReadOnly():
- raise ZODB.POSException.ReadOnlyError()
+ """Allocate a new object id."""
self._lock_acquire()
try:
return self._apply_all_storages('new_oid')
@@ -214,9 +227,8 @@
self._lock_release()
# XXX
+ @ensure_writable
def pack(self, t, referencesf):
- if self.isReadOnly():
- raise ZODB.POSException.ReadOnlyError()
self._apply_all_storages('pack', (t, referencesf))
# XXX
@@ -231,9 +243,8 @@
# XXX
@store_38_compatible
+ @ensure_writable
def store(self, oid, oldserial, data, transaction):
- if self.isReadOnly():
- raise ZODB.POSException.ReadOnlyError()
if transaction is not self._transaction:
raise ZODB.POSException.StorageTransactionError(self, transaction)
@@ -270,10 +281,8 @@
self._lock_release()
# XXX
+ @ensure_writable
def tpc_begin(self, transaction, tid=None, status=' '):
- if self.isReadOnly():
- raise ZODB.POSException.ReadOnlyError()
-
self._lock_acquire()
try:
if self._transaction is transaction:
@@ -352,6 +361,7 @@
# IBlobStorage
@storeBlob_38_compatible
+ @ensure_writable
def storeBlob(self, oid, oldserial, data, blob, transaction):
"""Stores data that has a BLOB attached."""
# XXX
@@ -372,9 +382,8 @@
return True
# XXX
+ @ensure_writable
def undo(self, transaction_id, transaction):
- if self.isReadOnly():
- raise ZODB.POSException.ReadOnlyError()
self._lock_acquire()
try:
return self._apply_all_storages('undo',
Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/tests/failingstorage.py
===================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/tests/failingstorage.py 2008-01-16 01:55:53 UTC (rev 82911)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/tests/failingstorage.py 2008-01-16 08:31:26 UTC (rev 82912)
@@ -17,6 +17,15 @@
return FailingStorage(self.name)
+def failing_method(name):
+ """Produces a method that can be made to fail."""
+ def fail(self, *args, **kw):
+ if name == self._fail:
+ raise Exception()
+ return getattr(ZODB.FileStorage.FileStorage, name)(self, *args, **kw)
+ return fail
+
+
class FailingStorage(ZODB.FileStorage.FileStorage):
_fail = None
@@ -33,20 +42,18 @@
def getExtensionMethods(self):
return dict(fail=None)
- def history(self, *args, **kw):
- if 'history' == self._fail:
- raise Exception()
- return ZODB.FileStorage.FileStorage.history(self, *args, **kw)
+ history = failing_method('history')
+ loadSerial = failing_method('loadSerial')
- def fail(self, method):
- if method in ['history']:
+ def fail(self, method_name):
+ if method_name in ['history', 'loadSerial']:
# Those methods are copied/references by the server code, we can't
# rebind them here.
- self._fail = method
+ self._fail = method_name
return
- old_method = getattr(self, method)
+ old_method = getattr(self, method_name)
def failing_method(*args, **kw):
- setattr(self, method, old_method)
+ setattr(self, method_name, old_method)
raise Exception()
- setattr(self, method, failing_method)
+ setattr(self, method_name, failing_method)
Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py
===================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py 2008-01-16 01:55:53 UTC (rev 82911)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py 2008-01-16 08:31:26 UTC (rev 82912)
@@ -128,7 +128,7 @@
zconf, port)
self._servers.append(adminaddr)
self._storages.append(ZEOOpener(zport, storage='1',
- cache_size=50,
+ cache_size=12,
min_disconnect_poll=0.5, wait=1,
wait_timeout=60))
self._storage = gocept.zeoraid.storage.RAIDStorage('teststorage',
@@ -148,6 +148,9 @@
backend_count = 2
+ def _disable_storage(self, index):
+ self._storage.raid_disable(self._storage.storages_optimal[index])
+
def test_close(self):
self._storage.close()
self.assertEquals(self._storage.closed, True)
@@ -215,11 +218,11 @@
self.assertEquals(1, len(self._backend(1).history(oid, '')))
self.assertEquals(1, len(self._storage.history(oid, '')))
- self._storage.raid_disable(self._storage.storages_optimal[0])
+ self._disable_storage(0)
self.assertEquals(1, len(self._backend(0).history(oid, '')))
self.assertEquals(1, len(self._storage.history(oid, '')))
- self._storage.raid_disable(self._storage.storages_optimal[0])
+ self._disable_storage(0)
self.assertRaises(gocept.zeoraid.interfaces.RAIDError,
self._storage.history, oid, '')
@@ -251,9 +254,9 @@
self.assertEquals(lt, self._backend(1).lastTransaction())
def test_lastTransaction_degrading(self):
- self._storage.raid_disable(self._storage.storages_optimal[0])
+ self._disable_storage(0)
self.assertEquals(ZODB.utils.z64, self._storage.lastTransaction())
- self._storage.raid_disable(self._storage.storages_optimal[0])
+ self._disable_storage(0)
self.assertEquals('failed', self._storage.raid_status())
self.assertRaises(gocept.zeoraid.interfaces.RAIDError,
self._storage.lastTransaction)
@@ -271,14 +274,14 @@
self.assertEquals(1, len(self._backend(0)))
self.assertEquals(1, len(self._backend(1)))
- self._storage.raid_disable(self._storage.storages_optimal[0])
+ self._disable_storage(0)
self._dostore(
revid='\x00\x00\x00\x00\x00\x00\x00\x02')
# See above. This shouldn't be 0 if ClientStorage worked correctly.
self.assertEquals(2, len(self._storage))
self.assertEquals(2, len(self._backend(0)))
- self._storage.raid_disable(self._storage.storages_optimal[0])
+ self._disable_storage(0)
self.assertRaises(gocept.zeoraid.interfaces.RAIDError,
self._storage.__len__)
@@ -299,7 +302,7 @@
self.assertEquals((data_record, serial), self._backend(0).load(oid))
self.assertEquals((data_record, serial), self._backend(1).load(oid))
- self._storage.raid_disable(self._storage.storages_optimal[0])
+ self._disable_storage(0)
self.assertEquals((data_record, serial), self._storage.load(oid))
self.assertEquals((data_record, serial), self._backend(0).load(oid))
@@ -309,11 +312,24 @@
self.assertEquals(self._storage.lastTransaction(), serial)
self.assertEquals((data_record, serial), self._backend(0).load(oid))
- self._storage.raid_disable(self._storage.storages_optimal[0])
+ self._disable_storage(0)
self.assertRaises(gocept.zeoraid.interfaces.RAIDError,
self._storage.load, oid)
+ def test_load_can_be_failed(self):
+ # ClientStorage does not directly call `load` but
+ # `loadEx` which in turn calls `load` on the storage.
+ # Unfortunately `storage.load` is also rebound onto the storage
+ # server so in the future the fail() might not work. To avoid
+ # hard-to-debug errors in the future, we test that fail('load')
+ # actually does make the `load` call fail.
+ oid = self._storage.new_oid()
+ self._backend(0).fail('load')
+ self.assertRaises(Exception, self._backend(0).load, oid)
+
def test_load_degrading2(self):
+ # If this test fails weirdly, please check that the test above works
+ # correctly before losing hair.
oid = self._storage.new_oid()
self._dostore(oid=oid, revid='\x00\x00\x00\x00\x00\x00\x00\x01')
self._backend(0).fail('load')
@@ -329,7 +345,6 @@
self._storage.load, oid)
self.assertEquals('failed', self._storage.raid_status())
-
def test_loadBefore_degrading1(self):
oid = self._storage.new_oid()
self.assertRaises(
@@ -354,13 +369,13 @@
self.assertEquals((data_record, serial, end_tid),
self._backend(1).loadBefore(oid, revid2))
- self._storage.raid_disable(self._storage.storages_optimal[0])
+ self._disable_storage(0)
self.assertEquals((data_record, serial, end_tid),
self._storage.loadBefore(oid, revid2))
self.assertEquals((data_record, serial, end_tid),
self._backend(0).loadBefore(oid, revid2))
- self._storage.raid_disable(self._storage.storages_optimal[0])
+ self._disable_storage(0)
self.assertRaises(gocept.zeoraid.interfaces.RAIDError,
self._storage.loadBefore, oid, revid2)
@@ -387,7 +402,69 @@
self._storage.loadBefore, oid, revid2)
self.assertEquals('failed', self._storage.raid_status())
+ def test_loadSerial_degrading1(self):
+ oid = self._storage.new_oid()
+ self.assertRaises(
+ ZODB.POSException.POSKeyError,
+ self._storage.loadSerial,
+ oid, '\x00\x00\x00\x00\x00\x00\x00\x01')
+ self.assertRaises(
+ ZODB.POSException.POSKeyError,
+ self._backend(0).loadSerial,
+ oid, '\x00\x00\x00\x00\x00\x00\x00\x01')
+ self.assertRaises(
+ ZODB.POSException.POSKeyError,
+ self._backend(1).loadSerial,
+ oid, '\x00\x00\x00\x00\x00\x00\x00\x01')
+ self.assertEquals('optimal', self._storage.raid_status())
+ revid = self._dostoreNP(oid=oid, revid=None, data='foo')
+ self._dostoreNP(oid=oid, revid=revid, data='bar')
+
+ data_record = self._storage.loadSerial(oid, revid)
+ self.assertEquals('foo', data_record)
+ self.assertEquals(data_record,
+ self._backend(0).loadSerial(oid, revid))
+ self.assertEquals(data_record,
+ self._backend(1).loadSerial(oid, revid))
+
+ self._disable_storage(0)
+ self.assertEquals(data_record,
+ self._storage.loadSerial(oid, revid))
+ self.assertEquals(data_record,
+ self._backend(0).loadSerial(oid, revid))
+
+ self._disable_storage(0)
+ self.assertRaises(gocept.zeoraid.interfaces.RAIDError,
+ self._storage.loadSerial, oid, revid)
+
+
+ def test_loadSerial_degrading2(self):
+ oid = self._storage.new_oid()
+ revid = self._dostoreNP(oid=oid, revid=None, data='foo')
+ self._dostoreNP(oid=oid, revid=revid, data='bar')
+
+ data_record = self._storage.loadSerial(oid, revid)
+ self.assertEquals('foo', data_record)
+ self.assertEquals(data_record,
+ self._backend(0).loadSerial(oid, revid))
+ self.assertEquals(data_record,
+ self._backend(1).loadSerial(oid, revid))
+ self.assertEquals('optimal', self._storage.raid_status())
+
+ self._backend(0).fail('loadSerial')
+ self.assertEquals(data_record,
+ self._storage.loadSerial(oid, revid))
+ self.assertEquals(data_record,
+ self._backend(0).loadSerial(oid, revid))
+ self.assertEquals('degraded', self._storage.raid_status())
+
+ self._backend(0).fail('loadSerial')
+ self.assertRaises(gocept.zeoraid.interfaces.RAIDError,
+ self._storage.loadSerial, oid, revid)
+ self.assertEquals('failed', self._storage.raid_status())
+
+
class ZEOReplicationStorageTests(ZEOStorageBackendTests,
ReplicationStorageTests,
ThreadTests.ThreadTests):
More information about the Checkins
mailing list