Commit 8be9150f authored by Vincent Pelletier's avatar Vincent Pelletier

Fix loadBefore.

There are 2 possibilities when an object is not found:
- the object doesn't exist at all
- the object exists, but nothing matches serial criterion

git-svn-id: https://svn.erp5.org/repos/neo/trunk@2256 71dcc9de-d417-0410-9af5-da40c76e7ee4
parent 01a49a24
...@@ -19,6 +19,7 @@ from ZODB import BaseStorage, ConflictResolution, POSException ...@@ -19,6 +19,7 @@ from ZODB import BaseStorage, ConflictResolution, POSException
from neo.client.app import Application from neo.client.app import Application
from neo.client.exception import NEOStorageNotFoundError from neo.client.exception import NEOStorageNotFoundError
from neo.client.exception import NEOStorageDoesNotExistError
def check_read_only(func): def check_read_only(func):
def wrapped(self, *args, **kw): def wrapped(self, *args, **kw):
...@@ -88,6 +89,8 @@ class Storage(BaseStorage.BaseStorage, ...@@ -88,6 +89,8 @@ class Storage(BaseStorage.BaseStorage,
def loadBefore(self, oid, tid): def loadBefore(self, oid, tid):
try: try:
return self.app.loadBefore(oid=oid, tid=tid) return self.app.loadBefore(oid=oid, tid=tid)
except NEOStorageDoesNotExistError:
raise POSException.POSKeyError(oid)
except NEOStorageNotFoundError: except NEOStorageNotFoundError:
return None return None
......
...@@ -464,6 +464,7 @@ class Application(object): ...@@ -464,6 +464,7 @@ class Application(object):
technical problem technical problem
NEOStorageNotFoundError NEOStorageNotFoundError
object exists but no data satisfies given parameters object exists but no data satisfies given parameters
NEOStorageDoesNotExistError
object doesn't exist object doesn't exist
""" """
# TODO: # TODO:
......
...@@ -25,3 +25,11 @@ class NEOStorageError(POSException.StorageError): ...@@ -25,3 +25,11 @@ class NEOStorageError(POSException.StorageError):
class NEOStorageNotFoundError(NEOStorageError): class NEOStorageNotFoundError(NEOStorageError):
pass pass
class NEOStorageDoesNotExistError(NEOStorageNotFoundError):
"""
This error is a refinement of NEOStorageNotFoundError: this means
that some object was not found, but also that it does not exist at all.
"""
pass
...@@ -23,6 +23,7 @@ from neo.client.handlers import BaseHandler, AnswerBaseHandler ...@@ -23,6 +23,7 @@ from neo.client.handlers import BaseHandler, AnswerBaseHandler
from neo.protocol import NodeTypes, ProtocolError, LockState from neo.protocol import NodeTypes, ProtocolError, LockState
from neo.util import dump from neo.util import dump
from neo.client.exception import NEOStorageError, NEOStorageNotFoundError from neo.client.exception import NEOStorageError, NEOStorageNotFoundError
from neo.client.exception import NEOStorageDoesNotExistError
class StorageEventHandler(BaseHandler): class StorageEventHandler(BaseHandler):
...@@ -116,6 +117,9 @@ class StorageAnswersHandler(AnswerBaseHandler): ...@@ -116,6 +117,9 @@ class StorageAnswersHandler(AnswerBaseHandler):
# - asking for history # - asking for history
raise NEOStorageNotFoundError(message) raise NEOStorageNotFoundError(message)
def oidDoesNotExist(self, conn, message):
raise NEOStorageDoesNotExistError(message)
def tidNotFound(self, conn, message): def tidNotFound(self, conn, message):
# This can happen when requiring txn informations # This can happen when requiring txn informations
raise NEOStorageNotFoundError(message) raise NEOStorageNotFoundError(message)
......
...@@ -362,6 +362,9 @@ class EventHandler(object): ...@@ -362,6 +362,9 @@ class EventHandler(object):
def oidNotFound(self, conn, message): def oidNotFound(self, conn, message):
raise UnexpectedPacketError raise UnexpectedPacketError
def oidDoesNotExist(self, conn, message):
raise UnexpectedPacketError
def tidNotFound(self, conn, message): def tidNotFound(self, conn, message):
raise UnexpectedPacketError raise UnexpectedPacketError
...@@ -466,6 +469,7 @@ class EventHandler(object): ...@@ -466,6 +469,7 @@ class EventHandler(object):
d[ErrorCodes.ACK] = self.ack d[ErrorCodes.ACK] = self.ack
d[ErrorCodes.NOT_READY] = self.notReady d[ErrorCodes.NOT_READY] = self.notReady
d[ErrorCodes.OID_NOT_FOUND] = self.oidNotFound d[ErrorCodes.OID_NOT_FOUND] = self.oidNotFound
d[ErrorCodes.OID_DOES_NOT_EXIST] = self.oidDoesNotExist
d[ErrorCodes.TID_NOT_FOUND] = self.tidNotFound d[ErrorCodes.TID_NOT_FOUND] = self.tidNotFound
d[ErrorCodes.PROTOCOL_ERROR] = self.protocolError d[ErrorCodes.PROTOCOL_ERROR] = self.protocolError
d[ErrorCodes.BROKEN_NODE] = self.brokenNodeDisallowedError d[ErrorCodes.BROKEN_NODE] = self.brokenNodeDisallowedError
......
...@@ -41,6 +41,7 @@ class ErrorCodes(Enum): ...@@ -41,6 +41,7 @@ class ErrorCodes(Enum):
ACK = Enum.Item(0) ACK = Enum.Item(0)
NOT_READY = Enum.Item(1) NOT_READY = Enum.Item(1)
OID_NOT_FOUND = Enum.Item(2) OID_NOT_FOUND = Enum.Item(2)
OID_DOES_NOT_EXIST = Enum.Item(6)
TID_NOT_FOUND = Enum.Item(3) TID_NOT_FOUND = Enum.Item(3)
PROTOCOL_ERROR = Enum.Item(4) PROTOCOL_ERROR = Enum.Item(4)
BROKEN_NODE = Enum.Item(5) BROKEN_NODE = Enum.Item(5)
...@@ -1853,6 +1854,7 @@ class ErrorRegistry(dict): ...@@ -1853,6 +1854,7 @@ class ErrorRegistry(dict):
ProtocolError = register_error(ErrorCodes.PROTOCOL_ERROR) ProtocolError = register_error(ErrorCodes.PROTOCOL_ERROR)
TidNotFound = register_error(ErrorCodes.TID_NOT_FOUND) TidNotFound = register_error(ErrorCodes.TID_NOT_FOUND)
OidNotFound = register_error(ErrorCodes.OID_NOT_FOUND) OidNotFound = register_error(ErrorCodes.OID_NOT_FOUND)
OidDoesNotExist = register_error(ErrorCodes.OID_DOES_NOT_EXIST)
NotReady = register_error(ErrorCodes.NOT_READY) NotReady = register_error(ErrorCodes.NOT_READY)
Broken = register_error(ErrorCodes.BROKEN_NODE) Broken = register_error(ErrorCodes.BROKEN_NODE)
......
...@@ -339,7 +339,13 @@ class MySQLDatabaseManager(DatabaseManager): ...@@ -339,7 +339,13 @@ class MySQLDatabaseManager(DatabaseManager):
if before_tid is not None: if before_tid is not None:
before_tid = u64(before_tid) before_tid = u64(before_tid)
result = self._getObject(oid, tid, before_tid) result = self._getObject(oid, tid, before_tid)
if result is not None: if result is None:
# See if object exists at all
result = self._getObject(oid)
if result is not None:
# Object exists
result = False
else:
serial, next_serial, compression, checksum, data, data_serial = \ serial, next_serial, compression, checksum, data, data_serial = \
result result
if data is None and resolve_data: if data is None and resolve_data:
......
...@@ -85,14 +85,17 @@ class BaseClientAndStorageOperationHandler(EventHandler): ...@@ -85,14 +85,17 @@ class BaseClientAndStorageOperationHandler(EventHandler):
app.queueEvent(self.askObject, conn, oid, serial, tid) app.queueEvent(self.askObject, conn, oid, serial, tid)
return return
o = self._askObject(oid, serial, tid) o = self._askObject(oid, serial, tid)
if o is not None: if o is None:
logging.debug('oid = %s does not exist', dump(oid))
p = Errors.OidDoesNotExist(dump(oid))
elif o is False:
logging.debug('oid = %s not found', dump(oid))
p = Errors.OidNotFound(dump(oid))
else:
serial, next_serial, compression, checksum, data, data_serial = o serial, next_serial, compression, checksum, data, data_serial = o
logging.debug('oid = %s, serial = %s, next_serial = %s', logging.debug('oid = %s, serial = %s, next_serial = %s',
dump(oid), dump(serial), dump(next_serial)) dump(oid), dump(serial), dump(next_serial))
p = Packets.AnswerObject(oid, serial, next_serial, p = Packets.AnswerObject(oid, serial, next_serial,
compression, checksum, data, data_serial) compression, checksum, data, data_serial)
else:
logging.debug('oid = %s not found', dump(oid))
p = Errors.OidNotFound('%s does not exist' % dump(oid))
conn.answer(p) conn.answer(p)
...@@ -22,6 +22,7 @@ from ZODB.POSException import StorageTransactionError, UndoError, ConflictError ...@@ -22,6 +22,7 @@ from ZODB.POSException import StorageTransactionError, UndoError, ConflictError
from neo.tests import NeoTestBase from neo.tests import NeoTestBase
from neo.client.app import Application from neo.client.app import Application
from neo.client.exception import NEOStorageError, NEOStorageNotFoundError from neo.client.exception import NEOStorageError, NEOStorageNotFoundError
from neo.client.exception import NEOStorageDoesNotExistError
from neo.protocol import Packet, Packets, Errors, INVALID_TID, INVALID_SERIAL from neo.protocol import Packet, Packets, Errors, INVALID_TID, INVALID_SERIAL
from neo.util import makeChecksum from neo.util import makeChecksum
...@@ -317,9 +318,9 @@ class ClientApplicationTests(NeoTestBase): ...@@ -317,9 +318,9 @@ class ClientApplicationTests(NeoTestBase):
oid = self.makeOID() oid = self.makeOID()
tid1 = self.makeTID(1) tid1 = self.makeTID(1)
tid2 = self.makeTID(2) tid2 = self.makeTID(2)
# object not found in NEO -> NEOStorageNotFoundError # object not found in NEO -> NEOStorageDoesNotExistError
self.assertTrue(oid not in mq) self.assertTrue(oid not in mq)
packet = Errors.OidNotFound('') packet = Errors.OidDoesNotExist('')
packet.setId(0) packet.setId(0)
cell = Mock({ 'getUUID': '\x00' * 16}) cell = Mock({ 'getUUID': '\x00' * 16})
conn = Mock({ conn = Mock({
...@@ -328,7 +329,7 @@ class ClientApplicationTests(NeoTestBase): ...@@ -328,7 +329,7 @@ class ClientApplicationTests(NeoTestBase):
}) })
app.pt = Mock({ 'getCellListForOID': [cell, ], }) app.pt = Mock({ 'getCellListForOID': [cell, ], })
app.cp = Mock({ 'getConnForCell' : conn}) app.cp = Mock({ 'getConnForCell' : conn})
self.assertRaises(NEOStorageNotFoundError, app.loadBefore, oid, tid2) self.assertRaises(NEOStorageDoesNotExistError, app.loadBefore, oid, tid2)
self.checkAskObject(conn) self.checkAskObject(conn)
# no visible version -> NEOStorageNotFoundError # no visible version -> NEOStorageNotFoundError
an_object = (1, oid, INVALID_SERIAL, None, 0, 0, '', None) an_object = (1, oid, INVALID_SERIAL, None, 0, 0, '', None)
......
...@@ -22,6 +22,7 @@ from neo.protocol import NodeTypes, LockState ...@@ -22,6 +22,7 @@ from neo.protocol import NodeTypes, LockState
from neo.client.handlers.storage import StorageBootstrapHandler, \ from neo.client.handlers.storage import StorageBootstrapHandler, \
StorageAnswersHandler StorageAnswersHandler
from neo.client.exception import NEOStorageError, NEOStorageNotFoundError from neo.client.exception import NEOStorageError, NEOStorageNotFoundError
from neo.client.exception import NEOStorageDoesNotExistError
from ZODB.POSException import ConflictError from ZODB.POSException import ConflictError
MARKER = [] MARKER = []
...@@ -217,6 +218,11 @@ class StorageAnswerHandlerTests(NeoTestBase): ...@@ -217,6 +218,11 @@ class StorageAnswerHandlerTests(NeoTestBase):
conn = self.getConnection() conn = self.getConnection()
self.assertRaises(NEOStorageNotFoundError, self.handler.oidNotFound, self.assertRaises(NEOStorageNotFoundError, self.handler.oidNotFound,
conn, 'message') conn, 'message')
def test_oidDoesNotExist(self):
conn = self.getConnection()
self.assertRaises(NEOStorageDoesNotExistError,
self.handler.oidDoesNotExist, conn, 'message')
def test_tidNotFound(self): def test_tidNotFound(self):
conn = self.getConnection() conn = self.getConnection()
......
...@@ -255,35 +255,45 @@ class StorageMySQSLdbTests(NeoTestBase): ...@@ -255,35 +255,45 @@ class StorageMySQSLdbTests(NeoTestBase):
def test_getObject(self): def test_getObject(self):
oid1, = self.getOIDs(1) oid1, = self.getOIDs(1)
tid1, tid2 = self.getTIDs(2) tid1, tid2 = self.getTIDs(2)
FOUND_BUT_NOT_VISIBLE = False
OBJECT_T1_NO_NEXT = (tid1, None, 1, 0, '', None)
OBJECT_T1_NEXT = (tid1, tid2, 1, 0, '', None)
OBJECT_T2 = (tid2, None, 1, 0, '', None)
txn1, objs1 = self.getTransaction([oid1]) txn1, objs1 = self.getTransaction([oid1])
txn2, objs2 = self.getTransaction([oid1]) txn2, objs2 = self.getTransaction([oid1])
# non-present # non-present
self.assertEqual(self.db.getObject(oid1), None)
self.assertEqual(self.db.getObject(oid1, tid1), None) self.assertEqual(self.db.getObject(oid1, tid1), None)
self.assertEqual(self.db.getObject(oid1, before_tid=tid1), None) self.assertEqual(self.db.getObject(oid1, before_tid=tid1), None)
# one non-commited version # one non-commited version
self.db.storeTransaction(tid1, objs1, txn1) self.db.storeTransaction(tid1, objs1, txn1)
self.assertEqual(self.db.getObject(oid1), None)
self.assertEqual(self.db.getObject(oid1, tid1), None) self.assertEqual(self.db.getObject(oid1, tid1), None)
self.assertEqual(self.db.getObject(oid1, before_tid=tid1), None)
# one commited version # one commited version
self.db.finishTransaction(tid1) self.db.finishTransaction(tid1)
result = self.db.getObject(oid1, tid1) self.assertEqual(self.db.getObject(oid1), OBJECT_T1_NO_NEXT)
self.assertEqual(result, (tid1, None, 1, 0, '', None)) self.assertEqual(self.db.getObject(oid1, tid1), OBJECT_T1_NO_NEXT)
self.assertEqual(self.db.getObject(oid1, before_tid=tid1), None) self.assertEqual(self.db.getObject(oid1, before_tid=tid1),
FOUND_BUT_NOT_VISIBLE)
# two version available, one non-commited # two version available, one non-commited
self.db.storeTransaction(tid2, objs2, txn2) self.db.storeTransaction(tid2, objs2, txn2)
result = self.db.getObject(oid1, tid1) self.assertEqual(self.db.getObject(oid1), OBJECT_T1_NO_NEXT)
self.assertEqual(result, (tid1, None, 1, 0, '', None)) self.assertEqual(self.db.getObject(oid1, tid1), OBJECT_T1_NO_NEXT)
self.assertEqual(self.db.getObject(oid1, before_tid=tid1), None) self.assertEqual(self.db.getObject(oid1, before_tid=tid1),
FOUND_BUT_NOT_VISIBLE)
self.assertEqual(self.db.getObject(oid1, tid2), FOUND_BUT_NOT_VISIBLE)
self.assertEqual(self.db.getObject(oid1, before_tid=tid2),
OBJECT_T1_NO_NEXT)
# two commited versions # two commited versions
self.db.finishTransaction(tid2) self.db.finishTransaction(tid2)
result = self.db.getObject(oid1, tid1) self.assertEqual(self.db.getObject(oid1), OBJECT_T2)
self.assertEqual(result, (tid1, None, 1, 0, '', None)) self.assertEqual(self.db.getObject(oid1, tid1), OBJECT_T1_NO_NEXT)
result = self.db.getObject(oid1, tid2) self.assertEqual(self.db.getObject(oid1, before_tid=tid1),
self.assertEqual(result, (tid2, None, 1, 0, '', None)) FOUND_BUT_NOT_VISIBLE)
result = self.db.getObject(oid1, before_tid=tid2) self.assertEqual(self.db.getObject(oid1, tid2), OBJECT_T2)
self.assertEqual(result, (tid1, tid2, 1, 0, '', None)) self.assertEqual(self.db.getObject(oid1, before_tid=tid2),
# no tid specified, return the last version OBJECT_T1_NEXT)
result = self.db.getObject(oid1)
self.assertEqual(result, (tid2, None, 1, 0, '', None))
def test_setPartitionTable(self): def test_setPartitionTable(self):
ptid = self.getPTID(1) ptid = self.getPTID(1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment