Commit d48930fe authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 48aa3a91
...@@ -81,8 +81,7 @@ class Storage(BaseStorage.BaseStorage, ...@@ -81,8 +81,7 @@ class Storage(BaseStorage.BaseStorage,
try: try:
return self.app.load(oid)[:2] return self.app.load(oid)[:2]
except NEOStorageNotFoundError: except NEOStorageNotFoundError:
raise raise POSException.POSKeyError(oid)
#raise POSException.POSKeyError(oid)
def new_oid(self): def new_oid(self):
return self.app.new_oid() return self.app.new_oid()
......
...@@ -330,8 +330,6 @@ class Application(ThreadedApplication): ...@@ -330,8 +330,6 @@ class Application(ThreadedApplication):
# TODO: # TODO:
# - rename parameters (here? and in handlers & packet definitions) # - rename parameters (here? and in handlers & packet definitions)
print 'QQQ client load oid: %r tid: %r before_tid: %r' % (oid, tid, before_tid)
acquire = self._cache_lock_acquire acquire = self._cache_lock_acquire
release = self._cache_lock_release release = self._cache_lock_release
# XXX: Consider using a more fine-grained lock. # XXX: Consider using a more fine-grained lock.
...@@ -352,7 +350,6 @@ class Application(ThreadedApplication): ...@@ -352,7 +350,6 @@ class Application(ThreadedApplication):
# Do not get something more recent than the last invalidation # Do not get something more recent than the last invalidation
# we got from master. # we got from master.
before_tid = p64(u64(self.last_tid) + 1) before_tid = p64(u64(self.last_tid) + 1)
print '\t.last_tid: %r' % self.last_tid
data, tid, next_tid, _ = self._loadFromStorage(oid, tid, before_tid) data, tid, next_tid, _ = self._loadFromStorage(oid, tid, before_tid)
acquire() acquire()
try: try:
...@@ -372,7 +369,6 @@ class Application(ThreadedApplication): ...@@ -372,7 +369,6 @@ class Application(ThreadedApplication):
return data, tid, next_tid return data, tid, next_tid
def _loadFromStorage(self, oid, at_tid, before_tid): def _loadFromStorage(self, oid, at_tid, before_tid):
print 'QQQ2 client loadFromStor oid: %r at_tid: %r before_tid: %r' % (oid, at_tid, before_tid)
packet = Packets.AskObject(oid, at_tid, before_tid) packet = Packets.AskObject(oid, at_tid, before_tid)
for node, conn in self.cp.iterateForObject(oid, readable=True): for node, conn in self.cp.iterateForObject(oid, readable=True):
try: try:
......
...@@ -28,7 +28,6 @@ from logging import getLogger, Formatter, Logger, StreamHandler, \ ...@@ -28,7 +28,6 @@ from logging import getLogger, Formatter, Logger, StreamHandler, \
from time import time from time import time
from traceback import format_exception from traceback import format_exception
import bz2, inspect, neo, os, signal, sqlite3, sys, threading import bz2, inspect, neo, os, signal, sqlite3, sys, threading
from cStringIO import StringIO
# Stats for storage node of matrix test (py2.7:SQLite) # Stats for storage node of matrix test (py2.7:SQLite)
RECORD_SIZE = ( 234360832 # extra memory used RECORD_SIZE = ( 234360832 # extra memory used
...@@ -226,13 +225,10 @@ class NEOLogger(Logger): ...@@ -226,13 +225,10 @@ class NEOLogger(Logger):
uuid_str(r.uuid), ip, port) uuid_str(r.uuid), ip, port)
msg = r.msg msg = r.msg
pktcls = protocol.StaticRegistry[r.code] pktcls = protocol.StaticRegistry[r.code]
#bmsg = StringIO(msg)
#hmsg = protocol.Packets.parse(bmsg, protocol.ParserState())
print 'PACKET %s %s\t%s\t%s\t%s %s' % (r.created, r._name, r.msg_id, print 'PACKET %s %s\t%s\t%s\t%s %s' % (r.created, r._name, r.msg_id,
pktcls.__name__, peer, r.pkt.decode()) pktcls.__name__, peer, r.pkt.decode())
if msg is not None: if msg is not None:
msg = buffer(msg) msg = buffer(msg)
self._db.execute("INSERT INTO packet VALUES (NULL,?,?,?,?,?,?)", self._db.execute("INSERT INTO packet VALUES (NULL,?,?,?,?,?,?)",
(r.created, r._name, r.msg_id, r.code, peer, msg)) (r.created, r._name, r.msg_id, r.code, peer, msg))
else: else:
......
...@@ -75,7 +75,7 @@ def ErrorCodes(): ...@@ -75,7 +75,7 @@ def ErrorCodes():
REPLICATION_ERROR REPLICATION_ERROR
CHECKING_ERROR CHECKING_ERROR
BACKEND_NOT_IMPLEMENTED BACKEND_NOT_IMPLEMENTED
READ_ONLY_ACCESS # TODO use it READ_ONLY_ACCESS
@Enum @Enum
def ClusterStates(): def ClusterStates():
...@@ -1400,7 +1400,6 @@ class NotifyReady(Packet): ...@@ -1400,7 +1400,6 @@ class NotifyReady(Packet):
""" """
pass pass
# NOTE
# replication # replication
class FetchTransactions(Packet): class FetchTransactions(Packet):
......
...@@ -142,5 +142,4 @@ class ClientROServiceHandler(ClientServiceHandler): ...@@ -142,5 +142,4 @@ class ClientROServiceHandler(ClientServiceHandler):
def askLastTransaction(self, conn): def askLastTransaction(self, conn):
assert self.app.backup_tid is not None # we are in BACKUPING mode assert self.app.backup_tid is not None # we are in BACKUPING mode
backup_tid = self.app.pt.getBackupTid() backup_tid = self.app.pt.getBackupTid()
print '\n\n\nASK LAST_TID -> %r\n' % backup_tid
conn.answer(Packets.AnswerLastTransaction(backup_tid)) conn.answer(Packets.AnswerLastTransaction(backup_tid))
...@@ -257,7 +257,6 @@ class ClientROOperationHandler(ClientOperationHandler): ...@@ -257,7 +257,6 @@ class ClientROOperationHandler(ClientOperationHandler):
def askObject(self, conn, oid, serial, tid): def askObject(self, conn, oid, serial, tid):
backup_tid = self.app.dm.getBackupTID() backup_tid = self.app.dm.getBackupTID()
print '\n\n\nASK OBJECT %r, %r, %r (backup_tid: %r)' % (oid, serial, tid, backup_tid)
if serial and serial > backup_tid: if serial and serial > backup_tid:
# obj lookup will find nothing, but return properly either # obj lookup will find nothing, but return properly either
# OidDoesNotExist or OidNotFound # OidDoesNotExist or OidNotFound
...@@ -269,9 +268,7 @@ class ClientROOperationHandler(ClientOperationHandler): ...@@ -269,9 +268,7 @@ class ClientROOperationHandler(ClientOperationHandler):
if not serial and not tid: if not serial and not tid:
tid = add64(backup_tid, 1) tid = add64(backup_tid, 1)
print '-> asking as oid: %r serial: %r tid: %r' % (oid, serial, tid)
super(ClientROOperationHandler, self).askObject(conn, oid, serial, tid) super(ClientROOperationHandler, self).askObject(conn, oid, serial, tid)
print '(ask object done)'
def askTIDsFrom(self, conn, min_tid, max_tid, length, partition): def askTIDsFrom(self, conn, min_tid, max_tid, length, partition):
backup_tid = self.app.dm.getBackupTID() backup_tid = self.app.dm.getBackupTID()
......
...@@ -19,10 +19,12 @@ from logging import getLogger, INFO, DEBUG ...@@ -19,10 +19,12 @@ from logging import getLogger, INFO, DEBUG
import random import random
import time import time
import transaction import transaction
from ZODB.POSException import ReadOnlyError, POSKeyError
import unittest import unittest
from collections import defaultdict from collections import defaultdict
from functools import wraps from functools import wraps
from neo.lib import logging from neo.lib import logging
from neo.client.exception import NEOStorageError
from neo.storage.checker import CHECK_COUNT from neo.storage.checker import CHECK_COUNT
from neo.storage.replicator import Replicator from neo.storage.replicator import Replicator
from neo.lib.connector import SocketConnector from neo.lib.connector import SocketConnector
...@@ -34,9 +36,6 @@ from neo.lib.util import p64 ...@@ -34,9 +36,6 @@ from neo.lib.util import p64
from .. import Patch from .. import Patch
from . import ConnectionFilter, NEOCluster, NEOThreadedTest, predictable_random from . import ConnectionFilter, NEOCluster, NEOThreadedTest, predictable_random
from ZODB.POSException import ReadOnlyError
from neo.client.exception import NEOStorageError
# dump log to stderr # dump log to stderr
logging.backlog(max_size=None) logging.backlog(max_size=None)
del logging.default_root_handler.handle del logging.default_root_handler.handle
...@@ -523,7 +522,7 @@ class ReplicationTests(NEOThreadedTest): ...@@ -523,7 +522,7 @@ class ReplicationTests(NEOThreadedTest):
@backup_test() @backup_test()
def testBackupReadAccess(self, backup): def testBackupReadOnlyAccess(self, backup):
"""Check backup cluster can be used in read-only mode by ZODB clients""" """Check backup cluster can be used in read-only mode by ZODB clients"""
B = backup B = backup
U = B.upstream U = B.upstream
...@@ -533,48 +532,83 @@ class ReplicationTests(NEOThreadedTest): ...@@ -533,48 +532,83 @@ class ReplicationTests(NEOThreadedTest):
oid_list = [] oid_list = []
tid_list = [] tid_list = []
for i in xrange(10): # S -> Sb link stops working during [cutoff, recover) test iterations
# commit new data to U cutoff = 4
txn = transaction.Transaction() recover = 7
Z.tpc_begin(txn) def delayReplication(conn, packet):
oid = Z.new_oid() return isinstance(packet, Packets.AnswerFetchTransactions)
Z.store(oid, None, '%s-%i' % (oid, i), '', txn)
Z.tpc_vote(txn) with ConnectionFilter() as f:
tid = Z.tpc_finish(txn) for i in xrange(10):
oid_list.append(oid) if i == cutoff:
tid_list.append(tid) f.add(delayReplication)
if i == recover:
# make sure data propagated to B # removes the filter and retransmits all packets that were
self.tic() # queued once first filtered packed was detected on a connection.
self.assertEqual(B.backup_tid, U.last_tid) f.remove(delayReplication)
self.assertEqual(B.last_tid, U.last_tid)
self.assertEqual(1, self.checkBackup(B)) # commit new data to U
txn = transaction.Transaction()
# read data from B and verify it is what it should be txn.note('test transaction %i' % i)
# XXX we open new storage every time because invalidations are not Z.tpc_begin(txn)
# yet implemented in read-only mode. oid = Z.new_oid()
Zb = B.getZODBStorage() Z.store(oid, None, '%s-%i' % (oid, i), '', txn)
for j, oid in enumerate(oid_list): Z.tpc_vote(txn)
data, serial = Zb.load(oid, '') tid = Z.tpc_finish(txn)
self.assertEqual(data, '%s-%s' % (oid, j)) oid_list.append(oid)
self.assertEqual(serial, tid_list[j]) tid_list.append(tid)
# close storage because client app is otherwise shared in threaded # make sure data propagated to B
# tests and we need to refresh last_tid on next run self.tic()
# (see above about invalidations not working) if cutoff <= i < recover:
Zb.close() self.assertLess(B.backup_tid, U.last_tid)
else:
# try to commit something to backup storage and make sure it is really read-only self.assertEqual(B.backup_tid, U.last_tid)
Zb = B.getZODBStorage() self.assertEqual(B.last_tid, U.last_tid)
Zb._cache._max_size = 0 # make stores do work in sync way self.assertEqual(1, self.checkBackup(B, max_tid=B.backup_tid))
txn = transaction.Transaction()
self.assertRaises(ReadOnlyError, Zb.tpc_begin, txn) # read data from B and verify it is what it should be
self.assertRaises(ReadOnlyError, Zb.new_oid) # XXX we open new ZODB storage every time because invalidations
self.assertRaises(ReadOnlyError, Zb.store, oid_list[-1], tid_list[-1], 'somedata', '', txn) # are not yet implemented in read-only mode.
# tpc_vote first checks whether there were store replies - thus not ReadOnlyError Zb = B.getZODBStorage()
self.assertRaises(NEOStorageError, Zb.tpc_vote, txn) for j, oid in enumerate(oid_list):
if cutoff <= i < recover and j >= cutoff:
Zb.close() self.assertRaises(POSKeyError, Zb.load, oid, '')
else:
data, serial = Zb.load(oid, '')
self.assertEqual(data, '%s-%s' % (oid, j))
self.assertEqual(serial, tid_list[j])
# verify how transaction log & friends behave under potentially not-yet-fully
# fetched backup state (transactions committed at [cutoff, recover) should
# not be there; otherwise transactions should be fully there)
Zb = B.getZODBStorage()
Btxn_list = list(Zb.iterator())
self.assertEqual(len(Btxn_list), cutoff if cutoff <= i < recover else i+1)
for j, txn in enumerate(Btxn_list):
self.assertEqual(txn.tid, tid_list[j])
self.assertEqual(txn.description, 'test transaction %i' % j)
obj_list = list(txn)
self.assertEqual(len(obj_list), 1)
obj = obj_list[0]
self.assertEqual(obj.oid, oid_list[j])
self.assertEqual(obj.data, '%s-%s' % (obj.oid, j))
# TODO test askObjectHistory once it is fixed
# try to commit something to backup storage and make sure it is really read-only
Zb._cache._max_size = 0 # make stores do work in sync way
txn = transaction.Transaction()
self.assertRaises(ReadOnlyError, Zb.tpc_begin, txn)
self.assertRaises(ReadOnlyError, Zb.new_oid)
self.assertRaises(ReadOnlyError, Zb.store, oid_list[-1], tid_list[-1], 'somedata', '', txn)
# tpc_vote first checks whether there were store replies - thus not ReadOnlyError
self.assertRaises(NEOStorageError, Zb.tpc_vote, txn)
# close storage because client app is otherwise shared in threaded
# tests and we need to refresh last_tid on next run
# (see above about invalidations not working)
Zb.close()
if __name__ == "__main__": if __name__ == "__main__":
......
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