Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neo
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
Kirill Smelkov
neo
Commits
4bedd3fc
Commit
4bedd3fc
authored
Nov 28, 2016
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Plain Diff
.
parents
0f30552f
8eb14b01
Changes
69
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
69 changed files
with
633 additions
and
839 deletions
+633
-839
.coveragerc
.coveragerc
+6
-0
README.rst
README.rst
+1
-1
neo/admin/app.py
neo/admin/app.py
+3
-8
neo/admin/handler.py
neo/admin/handler.py
+1
-8
neo/client/Storage.py
neo/client/Storage.py
+1
-1
neo/client/__init__.py
neo/client/__init__.py
+1
-1
neo/client/app.py
neo/client/app.py
+6
-7
neo/client/cache.py
neo/client/cache.py
+1
-1
neo/client/handlers/master.py
neo/client/handlers/master.py
+21
-25
neo/client/handlers/storage.py
neo/client/handlers/storage.py
+8
-9
neo/client/pool.py
neo/client/pool.py
+1
-1
neo/lib/bootstrap.py
neo/lib/bootstrap.py
+7
-10
neo/lib/connection.py
neo/lib/connection.py
+2
-2
neo/lib/connector.py
neo/lib/connector.py
+2
-2
neo/lib/handler.py
neo/lib/handler.py
+10
-0
neo/lib/locking.py
neo/lib/locking.py
+2
-2
neo/lib/node.py
neo/lib/node.py
+91
-211
neo/lib/patch.py
neo/lib/patch.py
+1
-1
neo/lib/protocol.py
neo/lib/protocol.py
+51
-58
neo/lib/threaded_app.py
neo/lib/threaded_app.py
+3
-3
neo/lib/util.py
neo/lib/util.py
+1
-1
neo/master/app.py
neo/master/app.py
+22
-18
neo/master/backup_app.py
neo/master/backup_app.py
+3
-3
neo/master/handlers/__init__.py
neo/master/handlers/__init__.py
+7
-10
neo/master/handlers/backup.py
neo/master/handlers/backup.py
+0
-6
neo/master/handlers/client.py
neo/master/handlers/client.py
+2
-4
neo/master/handlers/election.py
neo/master/handlers/election.py
+11
-2
neo/master/handlers/identification.py
neo/master/handlers/identification.py
+30
-9
neo/master/handlers/secondary.py
neo/master/handlers/secondary.py
+11
-21
neo/master/handlers/storage.py
neo/master/handlers/storage.py
+3
-5
neo/master/transactions.py
neo/master/transactions.py
+1
-1
neo/neoctl/app.py
neo/neoctl/app.py
+2
-2
neo/scripts/neolog.py
neo/scripts/neolog.py
+7
-8
neo/scripts/neostorage.py
neo/scripts/neostorage.py
+1
-1
neo/scripts/runner.py
neo/scripts/runner.py
+1
-5
neo/storage/app.py
neo/storage/app.py
+4
-7
neo/storage/checker.py
neo/storage/checker.py
+2
-2
neo/storage/database/manager.py
neo/storage/database/manager.py
+7
-7
neo/storage/database/mysqldb.py
neo/storage/database/mysqldb.py
+2
-2
neo/storage/handlers/__init__.py
neo/storage/handlers/__init__.py
+2
-2
neo/storage/handlers/client.py
neo/storage/handlers/client.py
+1
-8
neo/storage/handlers/identification.py
neo/storage/handlers/identification.py
+14
-20
neo/storage/handlers/initialization.py
neo/storage/handlers/initialization.py
+1
-4
neo/storage/replicator.py
neo/storage/replicator.py
+3
-2
neo/tests/__init__.py
neo/tests/__init__.py
+14
-4
neo/tests/client/testClientApp.py
neo/tests/client/testClientApp.py
+7
-12
neo/tests/client/testMasterHandler.py
neo/tests/client/testMasterHandler.py
+0
-63
neo/tests/functional/__init__.py
neo/tests/functional/__init__.py
+12
-18
neo/tests/functional/testClient.py
neo/tests/functional/testClient.py
+3
-3
neo/tests/functional/testMaster.py
neo/tests/functional/testMaster.py
+2
-2
neo/tests/functional/testStorage.py
neo/tests/functional/testStorage.py
+4
-4
neo/tests/master/testClientHandler.py
neo/tests/master/testClientHandler.py
+6
-16
neo/tests/master/testElectionHandler.py
neo/tests/master/testElectionHandler.py
+11
-9
neo/tests/master/testMasterApp.py
neo/tests/master/testMasterApp.py
+2
-2
neo/tests/master/testMasterPT.py
neo/tests/master/testMasterPT.py
+12
-13
neo/tests/master/testStorageHandler.py
neo/tests/master/testStorageHandler.py
+2
-2
neo/tests/master/testTransactions.py
neo/tests/master/testTransactions.py
+1
-1
neo/tests/storage/testIdentificationHandler.py
neo/tests/storage/testIdentificationHandler.py
+6
-3
neo/tests/storage/testStorageDBTests.py
neo/tests/storage/testStorageDBTests.py
+4
-4
neo/tests/storage/testTransactions.py
neo/tests/storage/testTransactions.py
+1
-1
neo/tests/testBootstrap.py
neo/tests/testBootstrap.py
+1
-1
neo/tests/testConnection.py
neo/tests/testConnection.py
+1
-1
neo/tests/testNodes.py
neo/tests/testNodes.py
+30
-112
neo/tests/testPT.py
neo/tests/testPT.py
+34
-40
neo/tests/testUtil.py
neo/tests/testUtil.py
+1
-1
neo/tests/threaded/test.py
neo/tests/threaded/test.py
+114
-18
neo/tests/threaded/testReplication.py
neo/tests/threaded/testReplication.py
+1
-1
tools/coverage-html
tools/coverage-html
+1
-1
tools/replication
tools/replication
+6
-6
No files found.
.coveragerc
0 → 100644
View file @
4bedd3fc
[run]
source = neo
omit =
neo/debug.py
neo/scripts/runner.py
neo/tests/*
README.rst
View file @
4bedd3fc
...
@@ -34,7 +34,7 @@ ZODB API is fully implemented except:
...
@@ -34,7 +34,7 @@ ZODB API is fully implemented except:
for garbage collection)
for garbage collection)
- blobs: not implemented (not considered yet)
- blobs: not implemented (not considered yet)
Any ZODB like FileStorage can be converted to NEO instanteously,
Any ZODB like FileStorage can be converted to NEO instant
an
eously,
which means the database is operational before all data are imported.
which means the database is operational before all data are imported.
There's also a tool to convert back to FileStorage.
There's also a tool to convert back to FileStorage.
...
...
neo/admin/app.py
View file @
4bedd3fc
...
@@ -105,13 +105,9 @@ class Application(BaseApplication):
...
@@ -105,13 +105,9 @@ class Application(BaseApplication):
"""
"""
self
.
cluster_state
=
None
self
.
cluster_state
=
None
# search, find, connect and identify to the primary master
# search, find, connect and identify to the primary master
bootstrap
=
BootstrapManager
(
self
,
self
.
name
,
NodeTypes
.
ADMIN
,
bootstrap
=
BootstrapManager
(
self
,
NodeTypes
.
ADMIN
,
self
.
server
)
self
.
uuid
,
self
.
server
)
self
.
master_node
,
self
.
master_conn
,
num_partitions
,
num_replicas
=
\
data
=
bootstrap
.
getPrimaryConnection
()
bootstrap
.
getPrimaryConnection
()
(
node
,
conn
,
uuid
,
num_partitions
,
num_replicas
)
=
data
self
.
master_node
=
node
self
.
master_conn
=
conn
self
.
uuid
=
uuid
if
self
.
pt
is
None
:
if
self
.
pt
is
None
:
self
.
pt
=
PartitionTable
(
num_partitions
,
num_replicas
)
self
.
pt
=
PartitionTable
(
num_partitions
,
num_replicas
)
...
@@ -125,7 +121,6 @@ class Application(BaseApplication):
...
@@ -125,7 +121,6 @@ class Application(BaseApplication):
# passive handler
# passive handler
self
.
master_conn
.
setHandler
(
self
.
master_event_handler
)
self
.
master_conn
.
setHandler
(
self
.
master_event_handler
)
self
.
master_conn
.
ask
(
Packets
.
AskClusterState
())
self
.
master_conn
.
ask
(
Packets
.
AskClusterState
())
self
.
master_conn
.
ask
(
Packets
.
AskNodeInformation
())
self
.
master_conn
.
ask
(
Packets
.
AskPartitionTable
())
self
.
master_conn
.
ask
(
Packets
.
AskPartitionTable
())
def
sendPartitionTable
(
self
,
conn
,
min_offset
,
max_offset
,
uuid
):
def
sendPartitionTable
(
self
,
conn
,
min_offset
,
max_offset
,
uuid
):
...
...
neo/admin/handler.py
View file @
4bedd3fc
...
@@ -74,7 +74,7 @@ class AdminEventHandler(EventHandler):
...
@@ -74,7 +74,7 @@ class AdminEventHandler(EventHandler):
class
MasterEventHandler
(
EventHandler
):
class
MasterEventHandler
(
EventHandler
):
""" This class is just used to dispa
ct
h message to right handler"""
""" This class is just used to dispa
tc
h message to right handler"""
def
_connectionLost
(
self
,
conn
):
def
_connectionLost
(
self
,
conn
):
app
=
self
.
app
app
=
self
.
app
...
@@ -106,11 +106,6 @@ class MasterEventHandler(EventHandler):
...
@@ -106,11 +106,6 @@ class MasterEventHandler(EventHandler):
def
answerClusterState
(
self
,
conn
,
state
):
def
answerClusterState
(
self
,
conn
,
state
):
self
.
app
.
cluster_state
=
state
self
.
app
.
cluster_state
=
state
def
answerNodeInformation
(
self
,
conn
):
# XXX: This will no more exists when the initialization module will be
# implemented for factorize code (as done for bootstrap)
logging
.
debug
(
"answerNodeInformation"
)
def
notifyPartitionChanges
(
self
,
conn
,
ptid
,
cell_list
):
def
notifyPartitionChanges
(
self
,
conn
,
ptid
,
cell_list
):
self
.
app
.
pt
.
update
(
ptid
,
cell_list
,
self
.
app
.
nm
)
self
.
app
.
pt
.
update
(
ptid
,
cell_list
,
self
.
app
.
nm
)
...
@@ -125,8 +120,6 @@ class MasterEventHandler(EventHandler):
...
@@ -125,8 +120,6 @@ class MasterEventHandler(EventHandler):
def
notifyClusterInformation
(
self
,
conn
,
cluster_state
):
def
notifyClusterInformation
(
self
,
conn
,
cluster_state
):
self
.
app
.
cluster_state
=
cluster_state
self
.
app
.
cluster_state
=
cluster_state
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
self
.
app
.
nm
.
update
(
node_list
)
class
MasterRequestEventHandler
(
EventHandler
):
class
MasterRequestEventHandler
(
EventHandler
):
""" This class handle all answer from primary master node"""
""" This class handle all answer from primary master node"""
...
...
neo/client/Storage.py
View file @
4bedd3fc
...
@@ -108,7 +108,7 @@ class Storage(BaseStorage.BaseStorage,
...
@@ -108,7 +108,7 @@ class Storage(BaseStorage.BaseStorage,
def
deleteObject
(
self
,
oid
,
serial
,
transaction
):
def
deleteObject
(
self
,
oid
,
serial
,
transaction
):
self
.
app
.
store
(
oid
,
serial
,
None
,
None
,
transaction
)
self
.
app
.
store
(
oid
,
serial
,
None
,
None
,
transaction
)
# mu
tl
iple revisions
# mu
lt
iple revisions
def
loadSerial
(
self
,
oid
,
serial
):
def
loadSerial
(
self
,
oid
,
serial
):
try
:
try
:
return
self
.
app
.
load
(
oid
,
serial
)[
0
]
return
self
.
app
.
load
(
oid
,
serial
)[
0
]
...
...
neo/client/__init__.py
View file @
4bedd3fc
...
@@ -87,4 +87,4 @@ def patch():
...
@@ -87,4 +87,4 @@ def patch():
patch
()
patch
()
import
app
# set up signal handers early enough to do it in the main thread
import
app
# set up signal hand
l
ers early enough to do it in the main thread
neo/client/app.py
View file @
4bedd3fc
...
@@ -132,7 +132,7 @@ class Application(ThreadedApplication):
...
@@ -132,7 +132,7 @@ class Application(ThreadedApplication):
self
.
_cache_lock_acquire
=
lock
.
acquire
self
.
_cache_lock_acquire
=
lock
.
acquire
self
.
_cache_lock_release
=
lock
.
release
self
.
_cache_lock_release
=
lock
.
release
# _connecting_to_master_node is used to prevent simultaneous master
# _connecting_to_master_node is used to prevent simultaneous master
# node connection attemps
# node connection attemp
t
s
self
.
_connecting_to_master_node
=
Lock
()
self
.
_connecting_to_master_node
=
Lock
()
self
.
compress
=
compress
self
.
compress
=
compress
...
@@ -240,10 +240,10 @@ class Application(ThreadedApplication):
...
@@ -240,10 +240,10 @@ class Application(ThreadedApplication):
self
.
notifications_handler
,
self
.
notifications_handler
,
node
=
self
.
trying_master_node
,
node
=
self
.
trying_master_node
,
dispatcher
=
self
.
dispatcher
)
dispatcher
=
self
.
dispatcher
)
p
=
Packets
.
RequestIdentification
(
NodeTypes
.
CLIENT
,
self
.
uuid
,
None
,
self
.
name
,
None
)
try
:
try
:
ask
(
conn
,
Packets
.
RequestIdentification
(
ask
(
conn
,
p
,
handler
=
handler
)
NodeTypes
.
CLIENT
,
self
.
uuid
,
None
,
self
.
name
),
handler
=
handler
)
except
ConnectionClosed
:
except
ConnectionClosed
:
continue
continue
# If we reached the primary master node, mark as connected
# If we reached the primary master node, mark as connected
...
@@ -256,7 +256,6 @@ class Application(ThreadedApplication):
...
@@ -256,7 +256,6 @@ class Application(ThreadedApplication):
# operational. Might raise ConnectionClosed so that the new
# operational. Might raise ConnectionClosed so that the new
# primary can be looked-up again.
# primary can be looked-up again.
logging
.
info
(
'Initializing from master'
)
logging
.
info
(
'Initializing from master'
)
ask
(
conn
,
Packets
.
AskNodeInformation
(),
handler
=
handler
)
ask
(
conn
,
Packets
.
AskPartitionTable
(),
handler
=
handler
)
ask
(
conn
,
Packets
.
AskPartitionTable
(),
handler
=
handler
)
ask
(
conn
,
Packets
.
AskLastTransaction
(),
handler
=
handler
)
ask
(
conn
,
Packets
.
AskLastTransaction
(),
handler
=
handler
)
if
self
.
pt
.
operational
():
if
self
.
pt
.
operational
():
...
@@ -324,7 +323,7 @@ class Application(ThreadedApplication):
...
@@ -324,7 +323,7 @@ class Application(ThreadedApplication):
object existed, but its creation was undone
object existed, but its creation was undone
Note that loadSerial is used during conflict resolution to load
Note that loadSerial is used during conflict resolution to load
object's current version, which is not visible to us normaly (it was
object's current version, which is not visible to us normal
l
y (it was
committed after our snapshot was taken).
committed after our snapshot was taken).
"""
"""
# TODO:
# TODO:
...
@@ -987,7 +986,7 @@ class Application(ThreadedApplication):
...
@@ -987,7 +986,7 @@ class Application(ThreadedApplication):
queue
=
txn_context
[
'queue'
]
queue
=
txn_context
[
'queue'
]
txn_context
[
'object_stored_counter_dict'
][
oid
]
=
{}
txn_context
[
'object_stored_counter_dict'
][
oid
]
=
{}
# ZODB.Connection performs calls 'checkCurrentSerialInTransaction'
# ZODB.Connection performs calls 'checkCurrentSerialInTransaction'
# after stores, and skips oids that have been succe
e
ssfully stored.
# after stores, and skips oids that have been successfully stored.
assert
oid
not
in
txn_context
[
'cache_dict'
],
(
oid
,
txn_context
)
assert
oid
not
in
txn_context
[
'cache_dict'
],
(
oid
,
txn_context
)
txn_context
[
'data_dict'
].
setdefault
(
oid
,
CHECKED_SERIAL
)
txn_context
[
'data_dict'
].
setdefault
(
oid
,
CHECKED_SERIAL
)
checked_nodes
=
txn_context
[
'checked_nodes'
]
checked_nodes
=
txn_context
[
'checked_nodes'
]
...
...
neo/client/cache.py
View file @
4bedd3fc
...
@@ -203,7 +203,7 @@ class ClientCache(object):
...
@@ -203,7 +203,7 @@ class ClientCache(object):
item
=
self
.
_load
(
oid
,
next_tid
)
item
=
self
.
_load
(
oid
,
next_tid
)
if
item
:
if
item
:
# We don't handle late invalidations for cached oids, because
# We don't handle late invalidations for cached oids, because
# the caller is not supposed to explicit
e
ly asks for tids after
# the caller is not supposed to explicitly asks for tids after
# app.last_tid (and the cache should be empty when app.last_tid
# app.last_tid (and the cache should be empty when app.last_tid
# is still None).
# is still None).
assert
item
.
tid
==
tid
,
(
item
,
tid
)
assert
item
.
tid
==
tid
,
(
item
,
tid
)
...
...
neo/client/handlers/master.py
View file @
4bedd3fc
...
@@ -30,6 +30,16 @@ class PrimaryBootstrapHandler(AnswerBaseHandler):
...
@@ -30,6 +30,16 @@ class PrimaryBootstrapHandler(AnswerBaseHandler):
self
.
app
.
trying_master_node
=
None
self
.
app
.
trying_master_node
=
None
conn
.
close
()
conn
.
close
()
def
answerPartitionTable
(
self
,
conn
,
ptid
,
row_list
):
assert
row_list
self
.
app
.
pt
.
load
(
ptid
,
row_list
,
self
.
app
.
nm
)
def
answerLastTransaction
(
*
args
):
pass
class
PrimaryNotificationsHandler
(
MTEventHandler
):
""" Handler that process the notifications from the primary master """
def
_acceptIdentification
(
self
,
node
,
uuid
,
num_partitions
,
def
_acceptIdentification
(
self
,
node
,
uuid
,
num_partitions
,
num_replicas
,
your_uuid
,
primary
,
known_master_list
):
num_replicas
,
your_uuid
,
primary
,
known_master_list
):
app
=
self
.
app
app
=
self
.
app
...
@@ -77,27 +87,13 @@ class PrimaryBootstrapHandler(AnswerBaseHandler):
...
@@ -77,27 +87,13 @@ class PrimaryBootstrapHandler(AnswerBaseHandler):
raise
ProtocolError
(
'No UUID supplied'
)
raise
ProtocolError
(
'No UUID supplied'
)
app
.
uuid
=
your_uuid
app
.
uuid
=
your_uuid
logging
.
info
(
'Got an UUID: %s'
,
dump
(
app
.
uuid
))
logging
.
info
(
'Got an UUID: %s'
,
dump
(
app
.
uuid
))
app
.
id_timestamp
=
None
# Always create partition table
# Always create partition table
app
.
pt
=
PartitionTable
(
num_partitions
,
num_replicas
)
app
.
pt
=
PartitionTable
(
num_partitions
,
num_replicas
)
def
answerPartitionTable
(
self
,
conn
,
ptid
,
row_list
):
assert
row_list
self
.
app
.
pt
.
load
(
ptid
,
row_list
,
self
.
app
.
nm
)
def
answerNodeInformation
(
self
,
conn
):
pass
def
answerLastTransaction
(
self
,
conn
,
ltid
):
def
answerLastTransaction
(
self
,
conn
,
ltid
):
pass
class
PrimaryNotificationsHandler
(
MTEventHandler
):
""" Handler that process the notifications from the primary master """
def
packetReceived
(
self
,
conn
,
packet
,
kw
=
{}):
if
type
(
packet
)
is
Packets
.
AnswerLastTransaction
:
app
=
self
.
app
app
=
self
.
app
ltid
=
packet
.
decode
()[
0
]
if
app
.
last_tid
!=
ltid
:
if
app
.
last_tid
!=
ltid
:
# Either we're connecting or we already know the last tid
# Either we're connecting or we already know the last tid
# via invalidations.
# via invalidations.
...
@@ -124,15 +120,15 @@ class PrimaryNotificationsHandler(MTEventHandler):
...
@@ -124,15 +120,15 @@ class PrimaryNotificationsHandler(MTEventHandler):
db
=
app
.
getDB
()
db
=
app
.
getDB
()
db
is
None
or
db
.
invalidateCache
()
db
is
None
or
db
.
invalidateCache
()
app
.
last_tid
=
ltid
app
.
last_tid
=
ltid
elif
type
(
packet
)
is
Packets
.
AnswerTransactionFinished
:
def
answerTransactionFinished
(
self
,
conn
,
_
,
tid
,
callback
,
cache_dict
):
app
=
self
.
app
app
=
self
.
app
app
.
last_tid
=
tid
=
packet
.
decode
()[
1
]
app
.
last_tid
=
tid
callback
=
kw
.
pop
(
'callback'
)
# Update cache
# Update cache
cache
=
app
.
_cache
cache
=
app
.
_cache
app
.
_cache_lock_acquire
()
app
.
_cache_lock_acquire
()
try
:
try
:
for
oid
,
data
in
kw
.
pop
(
'cache_dict'
)
.
iteritems
():
for
oid
,
data
in
cache_dict
.
iteritems
():
# Update ex-latest value in cache
# Update ex-latest value in cache
cache
.
invalidate
(
oid
,
tid
)
cache
.
invalidate
(
oid
,
tid
)
if
data
is
not
None
:
if
data
is
not
None
:
...
@@ -142,7 +138,6 @@ class PrimaryNotificationsHandler(MTEventHandler):
...
@@ -142,7 +138,6 @@ class PrimaryNotificationsHandler(MTEventHandler):
callback
(
tid
)
callback
(
tid
)
finally
:
finally
:
app
.
_cache_lock_release
()
app
.
_cache_lock_release
()
MTEventHandler
.
packetReceived
(
self
,
conn
,
packet
,
kw
)
def
connectionClosed
(
self
,
conn
):
def
connectionClosed
(
self
,
conn
):
app
=
self
.
app
app
=
self
.
app
...
@@ -185,13 +180,14 @@ class PrimaryNotificationsHandler(MTEventHandler):
...
@@ -185,13 +180,14 @@ class PrimaryNotificationsHandler(MTEventHandler):
self
.
app
.
pt
.
update
(
ptid
,
cell_list
,
self
.
app
.
nm
)
self
.
app
.
pt
.
update
(
ptid
,
cell_list
,
self
.
app
.
nm
)
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
nm
=
self
.
app
.
nm
super
(
PrimaryNotificationsHandler
,
self
).
notifyNodeInformation
(
nm
.
update
(
node_list
)
conn
,
node_list
)
# XXX: 'update' automatically closes DOWN nodes. Do we really want
# XXX: 'update' automatically closes DOWN nodes. Do we really want
# to do the same thing for nodes in other non-running states ?
# to do the same thing for nodes in other non-running states ?
for
node_type
,
addr
,
uuid
,
state
in
node_list
:
getByUUID
=
self
.
app
.
nm
.
getByUUID
if
state
!=
NodeStates
.
RUNNING
:
for
node
in
node_list
:
node
=
nm
.
getByUUID
(
uuid
)
if
node
[
3
]
!=
NodeStates
.
RUNNING
:
node
=
getByUUID
(
node
[
2
])
if
node
and
node
.
isConnected
():
if
node
and
node
.
isConnected
():
node
.
getConnection
().
close
()
node
.
getConnection
().
close
()
...
...
neo/client/handlers/storage.py
View file @
4bedd3fc
...
@@ -41,14 +41,6 @@ class StorageEventHandler(MTEventHandler):
...
@@ -41,14 +41,6 @@ class StorageEventHandler(MTEventHandler):
self
.
app
.
cp
.
removeConnection
(
node
)
self
.
app
.
cp
.
removeConnection
(
node
)
super
(
StorageEventHandler
,
self
).
connectionFailed
(
conn
)
super
(
StorageEventHandler
,
self
).
connectionFailed
(
conn
)
class
StorageBootstrapHandler
(
AnswerBaseHandler
):
""" Handler used when connecting to a storage node """
def
notReady
(
self
,
conn
,
message
):
conn
.
close
()
raise
NodeNotReady
(
message
)
def
_acceptIdentification
(
self
,
node
,
def
_acceptIdentification
(
self
,
node
,
uuid
,
num_partitions
,
num_replicas
,
your_uuid
,
primary
,
uuid
,
num_partitions
,
num_replicas
,
your_uuid
,
primary
,
master_list
):
master_list
):
...
@@ -57,6 +49,13 @@ class StorageBootstrapHandler(AnswerBaseHandler):
...
@@ -57,6 +49,13 @@ class StorageBootstrapHandler(AnswerBaseHandler):
primary
,
self
.
app
.
master_conn
)
primary
,
self
.
app
.
master_conn
)
assert
uuid
==
node
.
getUUID
(),
(
uuid
,
node
.
getUUID
())
assert
uuid
==
node
.
getUUID
(),
(
uuid
,
node
.
getUUID
())
class
StorageBootstrapHandler
(
AnswerBaseHandler
):
""" Handler used when connecting to a storage node """
def
notReady
(
self
,
conn
,
message
):
conn
.
close
()
raise
NodeNotReady
(
message
)
class
StorageAnswersHandler
(
AnswerBaseHandler
):
class
StorageAnswersHandler
(
AnswerBaseHandler
):
""" Handle all messages related to ZODB operations """
""" Handle all messages related to ZODB operations """
...
@@ -170,7 +169,7 @@ class StorageAnswersHandler(AnswerBaseHandler):
...
@@ -170,7 +169,7 @@ class StorageAnswersHandler(AnswerBaseHandler):
raise
ConflictError
,
'Lock wait timeout for oid %s on %r'
%
(
raise
ConflictError
,
'Lock wait timeout for oid %s on %r'
%
(
dump
(
oid
),
conn
)
dump
(
oid
),
conn
)
# HasLock design required that storage is multi-threaded so that
# HasLock design required that storage is multi-threaded so that
# it can answer to AskHasLock while processing store re
s
quests.
# it can answer to AskHasLock while processing store requests.
# This means that the 2 cases (granted to us or nobody) are legitimate,
# This means that the 2 cases (granted to us or nobody) are legitimate,
# either because it gave us the lock but is/was slow to store our data,
# either because it gave us the lock but is/was slow to store our data,
# or because the storage took a lot of time processing a previous
# or because the storage took a lot of time processing a previous
...
...
neo/client/pool.py
View file @
4bedd3fc
...
@@ -57,7 +57,7 @@ class ConnectionPool(object):
...
@@ -57,7 +57,7 @@ class ConnectionPool(object):
conn
=
MTClientConnection
(
app
,
app
.
storage_event_handler
,
node
,
conn
=
MTClientConnection
(
app
,
app
.
storage_event_handler
,
node
,
dispatcher
=
app
.
dispatcher
)
dispatcher
=
app
.
dispatcher
)
p
=
Packets
.
RequestIdentification
(
NodeTypes
.
CLIENT
,
p
=
Packets
.
RequestIdentification
(
NodeTypes
.
CLIENT
,
app
.
uuid
,
None
,
app
.
name
)
app
.
uuid
,
None
,
app
.
name
,
app
.
id_timestamp
)
try
:
try
:
app
.
_ask
(
conn
,
p
,
handler
=
app
.
storage_bootstrap_handler
)
app
.
_ask
(
conn
,
p
,
handler
=
app
.
storage_bootstrap_handler
)
except
ConnectionClosed
:
except
ConnectionClosed
:
...
...
neo/lib/bootstrap.py
View file @
4bedd3fc
...
@@ -26,7 +26,7 @@ class BootstrapManager(EventHandler):
...
@@ -26,7 +26,7 @@ class BootstrapManager(EventHandler):
"""
"""
accepted
=
False
accepted
=
False
def
__init__
(
self
,
app
,
n
ame
,
node_type
,
uuid
=
Non
e
,
server
=
None
):
def
__init__
(
self
,
app
,
n
ode_typ
e
,
server
=
None
):
"""
"""
Manage the bootstrap stage of a non-master node, it lookup for the
Manage the bootstrap stage of a non-master node, it lookup for the
primary master node, connect to it then returns when the master node
primary master node, connect to it then returns when the master node
...
@@ -35,12 +35,12 @@ class BootstrapManager(EventHandler):
...
@@ -35,12 +35,12 @@ class BootstrapManager(EventHandler):
self
.
primary
=
None
self
.
primary
=
None
self
.
server
=
server
self
.
server
=
server
self
.
node_type
=
node_type
self
.
node_type
=
node_type
self
.
uuid
=
uuid
self
.
name
=
name
self
.
num_replicas
=
None
self
.
num_replicas
=
None
self
.
num_partitions
=
None
self
.
num_partitions
=
None
self
.
current
=
None
self
.
current
=
None
uuid
=
property
(
lambda
self
:
self
.
app
.
uuid
)
def
announcePrimary
(
self
,
conn
):
def
announcePrimary
(
self
,
conn
):
# We found the primary master early enough to be notified of election
# We found the primary master early enough to be notified of election
# end. Lucky. Anyway, we must carry on with identification request, so
# end. Lucky. Anyway, we must carry on with identification request, so
...
@@ -55,7 +55,7 @@ class BootstrapManager(EventHandler):
...
@@ -55,7 +55,7 @@ class BootstrapManager(EventHandler):
EventHandler
.
connectionCompleted
(
self
,
conn
)
EventHandler
.
connectionCompleted
(
self
,
conn
)
self
.
current
.
setRunning
()
self
.
current
.
setRunning
()
conn
.
ask
(
Packets
.
RequestIdentification
(
self
.
node_type
,
self
.
uuid
,
conn
.
ask
(
Packets
.
RequestIdentification
(
self
.
node_type
,
self
.
uuid
,
self
.
server
,
self
.
nam
e
))
self
.
server
,
self
.
app
.
name
,
Non
e
))
def
connectionFailed
(
self
,
conn
):
def
connectionFailed
(
self
,
conn
):
"""
"""
...
@@ -106,8 +106,9 @@ class BootstrapManager(EventHandler):
...
@@ -106,8 +106,9 @@ class BootstrapManager(EventHandler):
self
.
num_replicas
=
num_replicas
self
.
num_replicas
=
num_replicas
if
self
.
uuid
!=
your_uuid
:
if
self
.
uuid
!=
your_uuid
:
# got an uuid from the primary master
# got an uuid from the primary master
self
.
uuid
=
your_uuid
self
.
app
.
uuid
=
your_uuid
logging
.
info
(
'Got a new UUID: %s'
,
uuid_str
(
self
.
uuid
))
logging
.
info
(
'Got a new UUID: %s'
,
uuid_str
(
self
.
uuid
))
self
.
app
.
id_timestamp
=
None
self
.
accepted
=
True
self
.
accepted
=
True
def
getPrimaryConnection
(
self
):
def
getPrimaryConnection
(
self
):
...
@@ -141,8 +142,4 @@ class BootstrapManager(EventHandler):
...
@@ -141,8 +142,4 @@ class BootstrapManager(EventHandler):
continue
continue
# still processing
# still processing
poll
(
1
)
poll
(
1
)
return
(
self
.
current
,
conn
,
self
.
uuid
,
self
.
num_partitions
,
return
self
.
current
,
conn
,
self
.
num_partitions
,
self
.
num_replicas
self
.
num_replicas
)
neo/lib/connection.py
View file @
4bedd3fc
...
@@ -72,7 +72,7 @@ class HandlerSwitcher(object):
...
@@ -72,7 +72,7 @@ class HandlerSwitcher(object):
_pending
=
self
.
_pending
_pending
=
self
.
_pending
if
self
.
_is_handling
:
if
self
.
_is_handling
:
# If this is called while handling a packet, the response is to
# If this is called while handling a packet, the response is to
# be ex
c
pected for the current handler...
# be expected for the current handler...
(
request_dict
,
_
)
=
_pending
[
0
]
(
request_dict
,
_
)
=
_pending
[
0
]
else
:
else
:
# ...otherwise, queue for the latest handler
# ...otherwise, queue for the latest handler
...
@@ -100,7 +100,7 @@ class HandlerSwitcher(object):
...
@@ -100,7 +100,7 @@ class HandlerSwitcher(object):
# on_timeout sent a packet with a smaller timeout
# on_timeout sent a packet with a smaller timeout
# so keep the connection open
# so keep the connection open
return
return
# Notify that a timeout occured
# Notify that a timeout occur
r
ed
return
msg_id
return
msg_id
def
handle
(
self
,
connection
,
packet
):
def
handle
(
self
,
connection
,
packet
):
...
...
neo/lib/connector.py
View file @
4bedd3fc
...
@@ -124,8 +124,8 @@ class SocketConnector(object):
...
@@ -124,8 +124,8 @@ class SocketConnector(object):
def
getDescriptor
(
self
):
def
getDescriptor
(
self
):
# this descriptor must only be used by the event manager, where it
# this descriptor must only be used by the event manager, where it
# guarantee uni
city only while the connector is opened and registere
d
# guarantee uni
queness only while the connector is opened an
d
# in epoll
#
registered
in epoll
return
self
.
socket_fd
return
self
.
socket_fd
@
staticmethod
@
staticmethod
...
...
neo/lib/handler.py
View file @
4bedd3fc
...
@@ -165,6 +165,10 @@ class EventHandler(object):
...
@@ -165,6 +165,10 @@ class EventHandler(object):
return
return
conn
.
close
()
conn
.
close
()
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
app
=
self
.
app
app
.
nm
.
update
(
app
,
node_list
)
def
ping
(
self
,
conn
):
def
ping
(
self
,
conn
):
conn
.
answer
(
Packets
.
Pong
())
conn
.
answer
(
Packets
.
Pong
())
...
@@ -227,6 +231,9 @@ class MTEventHandler(EventHandler):
...
@@ -227,6 +231,9 @@ class MTEventHandler(EventHandler):
def
packetReceived
(
self
,
conn
,
packet
,
kw
=
{}):
def
packetReceived
(
self
,
conn
,
packet
,
kw
=
{}):
"""Redirect all received packet to dispatcher thread."""
"""Redirect all received packet to dispatcher thread."""
if
packet
.
isResponse
():
if
packet
.
isResponse
():
if
packet
.
poll_thread
:
self
.
dispatch
(
conn
,
packet
,
kw
)
kw
=
{}
if
not
(
self
.
dispatcher
.
dispatch
(
conn
,
packet
.
getId
(),
packet
,
kw
)
if
not
(
self
.
dispatcher
.
dispatch
(
conn
,
packet
.
getId
(),
packet
,
kw
)
or
type
(
packet
)
is
Packets
.
Pong
):
or
type
(
packet
)
is
Packets
.
Pong
):
raise
ProtocolError
(
'Unexpected response packet from %r: %r'
raise
ProtocolError
(
'Unexpected response packet from %r: %r'
...
@@ -254,3 +261,6 @@ class AnswerBaseHandler(EventHandler):
...
@@ -254,3 +261,6 @@ class AnswerBaseHandler(EventHandler):
packetReceived
=
unexpectedInAnswerHandler
packetReceived
=
unexpectedInAnswerHandler
peerBroken
=
unexpectedInAnswerHandler
peerBroken
=
unexpectedInAnswerHandler
protocolError
=
unexpectedInAnswerHandler
protocolError
=
unexpectedInAnswerHandler
def
acceptIdentification
(
*
args
):
pass
neo/lib/locking.py
View file @
4bedd3fc
...
@@ -12,7 +12,7 @@ from Queue import Empty
...
@@ -12,7 +12,7 @@ from Queue import Empty
Python threading module contains a simple logging mechanism, but:
Python threading module contains a simple logging mechanism, but:
- It's limitted to RLock class
- It's limitted to RLock class
- It's enabled instance by instance
- It's enabled instance by instance
- Choice to log or not is done at instan
c
iation
- Choice to log or not is done at instan
t
iation
- It does not emit any log before trying to acquire lock
- It does not emit any log before trying to acquire lock
This file defines a VerboseLock class implementing basic lock API and
This file defines a VerboseLock class implementing basic lock API and
...
@@ -29,7 +29,7 @@ class LockUser(object):
...
@@ -29,7 +29,7 @@ class LockUser(object):
def
__init__
(
self
,
message
,
level
=
0
):
def
__init__
(
self
,
message
,
level
=
0
):
t
=
threading
.
currentThread
()
t
=
threading
.
currentThread
()
ident
=
getattr
(
t
,
'node_name'
,
t
.
name
)
ident
=
getattr
(
t
,
'node_name'
,
t
.
name
)
# This class is instan
c
iated from a place desiring to known what
# This class is instan
t
iated from a place desiring to known what
# called it.
# called it.
# limit=1 would return execution position in this method
# limit=1 would return execution position in this method
# limit=2 would return execution position in caller
# limit=2 would return execution position in caller
...
...
neo/lib/node.py
View file @
4bedd3fc
This diff is collapsed.
Click to expand it.
neo/lib/patch.py
View file @
4bedd3fc
...
@@ -16,7 +16,7 @@
...
@@ -16,7 +16,7 @@
#
#
def
speedupFileStorageTxnLookup
():
def
speedupFileStorageTxnLookup
():
"""Speed up lookup of start position when instan
c
iating an iterator
"""Speed up lookup of start position when instan
t
iating an iterator
FileStorage does not index the file positions of transactions.
FileStorage does not index the file positions of transactions.
With this patch, we use the existing {oid->file_pos} index to bisect the
With this patch, we use the existing {oid->file_pos} index to bisect the
...
...
neo/lib/protocol.py
View file @
4bedd3fc
...
@@ -20,7 +20,7 @@ import traceback
...
@@ -20,7 +20,7 @@ import traceback
from
cStringIO
import
StringIO
from
cStringIO
import
StringIO
from
struct
import
Struct
from
struct
import
Struct
PROTOCOL_VERSION
=
7
PROTOCOL_VERSION
=
8
# Size restrictions.
# Size restrictions.
MIN_PACKET_SIZE
=
10
MIN_PACKET_SIZE
=
10
...
@@ -235,6 +235,7 @@ class Packet(object):
...
@@ -235,6 +235,7 @@ class Packet(object):
_code
=
None
_code
=
None
_fmt
=
None
_fmt
=
None
_id
=
None
_id
=
None
poll_thread
=
False
def
__init__
(
self
,
*
args
,
**
kw
):
def
__init__
(
self
,
*
args
,
**
kw
):
assert
self
.
_code
is
not
None
,
"Packet class not registered"
assert
self
.
_code
is
not
None
,
"Packet class not registered"
...
@@ -330,7 +331,7 @@ class ParseError(Exception):
...
@@ -330,7 +331,7 @@ class ParseError(Exception):
class
PItem
(
object
):
class
PItem
(
object
):
"""
"""
Base class for any packet item, _encode and _decode must be overriden
Base class for any packet item, _encode and _decode must be overrid
d
en
by subclasses.
by subclasses.
"""
"""
def
__init__
(
self
,
name
):
def
__init__
(
self
,
name
):
...
@@ -386,9 +387,9 @@ class PStructItem(PItem):
...
@@ -386,9 +387,9 @@ class PStructItem(PItem):
"""
"""
A single value encoded with struct
A single value encoded with struct
"""
"""
def
__init__
(
self
,
name
,
fmt
):
def
__init__
(
self
,
name
):
PItem
.
__init__
(
self
,
name
)
PItem
.
__init__
(
self
,
name
)
struct
=
Struct
(
fmt
)
struct
=
Struct
(
self
.
_
fmt
)
self
.
pack
=
struct
.
pack
self
.
pack
=
struct
.
pack
self
.
unpack
=
struct
.
unpack
self
.
unpack
=
struct
.
unpack
self
.
size
=
struct
.
size
self
.
size
=
struct
.
size
...
@@ -399,12 +400,23 @@ class PStructItem(PItem):
...
@@ -399,12 +400,23 @@ class PStructItem(PItem):
def
_decode
(
self
,
reader
):
def
_decode
(
self
,
reader
):
return
self
.
unpack
(
reader
(
self
.
size
))[
0
]
return
self
.
unpack
(
reader
(
self
.
size
))[
0
]
class
PStructItemOrNone
(
PStructItem
):
def
_encode
(
self
,
writer
,
value
):
return
writer
(
self
.
_None
if
value
is
None
else
self
.
pack
(
value
))
def
_decode
(
self
,
reader
):
value
=
reader
(
self
.
size
)
return
None
if
value
==
self
.
_None
else
self
.
unpack
(
value
)[
0
]
class
PList
(
PStructItem
):
class
PList
(
PStructItem
):
"""
"""
A list of homogeneous items
A list of homogeneous items
"""
"""
_fmt
=
'!L'
def
__init__
(
self
,
name
,
item
):
def
__init__
(
self
,
name
,
item
):
PStructItem
.
__init__
(
self
,
name
,
'!L'
)
PStructItem
.
__init__
(
self
,
name
)
self
.
_item
=
item
self
.
_item
=
item
def
_encode
(
self
,
writer
,
items
):
def
_encode
(
self
,
writer
,
items
):
...
@@ -422,8 +434,10 @@ class PDict(PStructItem):
...
@@ -422,8 +434,10 @@ class PDict(PStructItem):
"""
"""
A dictionary with custom key and value formats
A dictionary with custom key and value formats
"""
"""
_fmt
=
'!L'
def
__init__
(
self
,
name
,
key
,
value
):
def
__init__
(
self
,
name
,
key
,
value
):
PStructItem
.
__init__
(
self
,
name
,
'!L'
)
PStructItem
.
__init__
(
self
,
name
)
self
.
_key
=
key
self
.
_key
=
key
self
.
_value
=
value
self
.
_value
=
value
...
@@ -449,15 +463,15 @@ class PEnum(PStructItem):
...
@@ -449,15 +463,15 @@ class PEnum(PStructItem):
"""
"""
Encapsulate an enumeration value
Encapsulate an enumeration value
"""
"""
_fmt
=
'!l'
def
__init__
(
self
,
name
,
enum
):
def
__init__
(
self
,
name
,
enum
):
PStructItem
.
__init__
(
self
,
name
,
'!l'
)
PStructItem
.
__init__
(
self
,
name
)
self
.
_enum
=
enum
self
.
_enum
=
enum
def
_encode
(
self
,
writer
,
item
):
def
_encode
(
self
,
writer
,
item
):
if
item
is
None
:
if
item
is
None
:
item
=
-
1
item
=
-
1
else
:
assert
isinstance
(
item
,
int
),
item
writer
(
self
.
pack
(
item
))
writer
(
self
.
pack
(
item
))
def
_decode
(
self
,
reader
):
def
_decode
(
self
,
reader
):
...
@@ -474,8 +488,7 @@ class PString(PStructItem):
...
@@ -474,8 +488,7 @@ class PString(PStructItem):
"""
"""
A variable-length string
A variable-length string
"""
"""
def
__init__
(
self
,
name
):
_fmt
=
'!L'
PStructItem
.
__init__
(
self
,
name
,
'!L'
)
def
_encode
(
self
,
writer
,
value
):
def
_encode
(
self
,
writer
,
value
):
writer
(
self
.
pack
(
len
(
value
)))
writer
(
self
.
pack
(
len
(
value
)))
...
@@ -512,46 +525,26 @@ class PBoolean(PStructItem):
...
@@ -512,46 +525,26 @@ class PBoolean(PStructItem):
"""
"""
A boolean value, encoded as a single byte
A boolean value, encoded as a single byte
"""
"""
def
__init__
(
self
,
name
):
_fmt
=
'!?'
PStructItem
.
__init__
(
self
,
name
,
'!B'
)
def
_encode
(
self
,
writer
,
value
):
writer
(
self
.
pack
(
bool
(
value
)))
def
_decode
(
self
,
reader
):
return
bool
(
self
.
unpack
(
reader
(
self
.
size
))[
0
])
class
PNumber
(
PStructItem
):
class
PNumber
(
PStructItem
):
"""
"""
A integer number (4-bytes length)
A integer number (4-bytes length)
"""
"""
def
__init__
(
self
,
name
):
_fmt
=
'!L'
PStructItem
.
__init__
(
self
,
name
,
'!L'
)
class
PIndex
(
PStructItem
):
class
PIndex
(
PStructItem
):
"""
"""
A big integer to defined indexes in a huge list.
A big integer to defined indexes in a huge list.
"""
"""
def
__init__
(
self
,
name
):
_fmt
=
'!Q'
PStructItem
.
__init__
(
self
,
name
,
'!Q'
)
class
PPTID
(
PStructItem
):
class
PPTID
(
PStructItem
OrNone
):
"""
"""
A None value means an invalid PTID
A None value means an invalid PTID
"""
"""
def
__init__
(
self
,
name
):
_fmt
=
'!Q'
PStructItem
.
__init__
(
self
,
name
,
'!Q'
)
_None
=
Struct
(
_fmt
).
pack
(
0
)
def
_encode
(
self
,
writer
,
value
):
if
value
is
None
:
value
=
0
PStructItem
.
_encode
(
self
,
writer
,
value
)
def
_decode
(
self
,
reader
):
value
=
PStructItem
.
_decode
(
self
,
reader
)
if
value
==
0
:
value
=
None
return
value
class
PProtocol
(
PNumber
):
class
PProtocol
(
PNumber
):
"""
"""
...
@@ -577,18 +570,12 @@ class PChecksum(PItem):
...
@@ -577,18 +570,12 @@ class PChecksum(PItem):
def
_decode
(
self
,
reader
):
def
_decode
(
self
,
reader
):
return
reader
(
20
)
return
reader
(
20
)
class
PUUID
(
PStructItem
):
class
PUUID
(
PStructItem
OrNone
):
"""
"""
An UUID (node identifier, 4-bytes signed integer)
An UUID (node identifier, 4-bytes signed integer)
"""
"""
def
__init__
(
self
,
name
):
_fmt
=
'!l'
PStructItem
.
__init__
(
self
,
name
,
'!l'
)
_None
=
Struct
(
_fmt
).
pack
(
0
)
def
_encode
(
self
,
writer
,
uuid
):
writer
(
self
.
pack
(
uuid
or
0
))
def
_decode
(
self
,
reader
):
return
self
.
unpack
(
reader
(
self
.
size
))[
0
]
or
None
class
PTID
(
PItem
):
class
PTID
(
PItem
):
"""
"""
...
@@ -609,6 +596,13 @@ class PTID(PItem):
...
@@ -609,6 +596,13 @@ class PTID(PItem):
# same definition, for now
# same definition, for now
POID
=
PTID
POID
=
PTID
class
PFloat
(
PStructItemOrNone
):
"""
A float number (8-bytes length)
"""
_fmt
=
'!d'
_None
=
'
\
xff
'
*
8
# common definitions
# common definitions
PFEmpty
=
PStruct
(
'no_content'
)
PFEmpty
=
PStruct
(
'no_content'
)
...
@@ -622,6 +616,7 @@ PFNodeList = PList('node_list',
...
@@ -622,6 +616,7 @@ PFNodeList = PList('node_list',
PAddress
(
'address'
),
PAddress
(
'address'
),
PUUID
(
'uuid'
),
PUUID
(
'uuid'
),
PFNodeState
,
PFNodeState
,
PFloat
(
'id_timestamp'
),
),
),
)
)
...
@@ -695,6 +690,7 @@ class RequestIdentification(Packet):
...
@@ -695,6 +690,7 @@ class RequestIdentification(Packet):
Request a node identification. This must be the first packet for any
Request a node identification. This must be the first packet for any
connection. Any -> Any.
connection. Any -> Any.
"""
"""
poll_thread
=
True
_fmt
=
PStruct
(
'request_identification'
,
_fmt
=
PStruct
(
'request_identification'
,
PProtocol
(
'protocol_version'
),
PProtocol
(
'protocol_version'
),
...
@@ -702,6 +698,7 @@ class RequestIdentification(Packet):
...
@@ -702,6 +698,7 @@ class RequestIdentification(Packet):
PUUID
(
'uuid'
),
PUUID
(
'uuid'
),
PAddress
(
'address'
),
PAddress
(
'address'
),
PString
(
'name'
),
PString
(
'name'
),
PFloat
(
'id_timestamp'
),
)
)
_answer
=
PStruct
(
'accept_identification'
,
_answer
=
PStruct
(
'accept_identification'
,
...
@@ -882,6 +879,8 @@ class FinishTransaction(Packet):
...
@@ -882,6 +879,8 @@ class FinishTransaction(Packet):
Finish a transaction. C -> PM.
Finish a transaction. C -> PM.
Answer when a transaction is finished. PM -> C.
Answer when a transaction is finished. PM -> C.
"""
"""
poll_thread
=
True
_fmt
=
PStruct
(
'ask_finish_transaction'
,
_fmt
=
PStruct
(
'ask_finish_transaction'
,
PTID
(
'tid'
),
PTID
(
'tid'
),
PFOidList
,
PFOidList
,
...
@@ -1167,12 +1166,6 @@ class NotifyNodeInformation(Packet):
...
@@ -1167,12 +1166,6 @@ class NotifyNodeInformation(Packet):
PFNodeList
,
PFNodeList
,
)
)
class
NodeInformation
(
Packet
):
"""
Ask node information
"""
_answer
=
PFEmpty
class
SetClusterState
(
Packet
):
class
SetClusterState
(
Packet
):
"""
"""
Set the cluster state
Set the cluster state
...
@@ -1388,6 +1381,7 @@ class LastTransaction(Packet):
...
@@ -1388,6 +1381,7 @@ class LastTransaction(Packet):
Answer last committed TID.
Answer last committed TID.
M -> C
M -> C
"""
"""
poll_thread
=
True
_answer
=
PStruct
(
'answer_last_transaction'
,
_answer
=
PStruct
(
'answer_last_transaction'
,
PTID
(
'tid'
),
PTID
(
'tid'
),
...
@@ -1492,8 +1486,8 @@ class Replicate(Packet):
...
@@ -1492,8 +1486,8 @@ class Replicate(Packet):
class
ReplicationDone
(
Packet
):
class
ReplicationDone
(
Packet
):
"""
"""
Notify the master node that a partition has been success
ully replicated from
Notify the master node that a partition has been success
fully replicated
a storage to another.
from
a storage to another.
S -> M
S -> M
"""
"""
_fmt
=
PStruct
(
'notify_replication_done'
,
_fmt
=
PStruct
(
'notify_replication_done'
,
...
@@ -1528,7 +1522,7 @@ def register(request, ignore_when_closed=None):
...
@@ -1528,7 +1522,7 @@ def register(request, ignore_when_closed=None):
# By default, on a closed connection:
# By default, on a closed connection:
# - request: ignore
# - request: ignore
# - answer: keep
# - answer: keep
# - no
fit
ication: keep
# - no
tif
ication: keep
ignore_when_closed
=
answer
is
not
None
ignore_when_closed
=
answer
is
not
None
request
.
_ignore_when_closed
=
ignore_when_closed
request
.
_ignore_when_closed
=
ignore_when_closed
if
answer
in
(
Error
,
None
):
if
answer
in
(
Error
,
None
):
...
@@ -1536,6 +1530,7 @@ def register(request, ignore_when_closed=None):
...
@@ -1536,6 +1530,7 @@ def register(request, ignore_when_closed=None):
# build a class for the answer
# build a class for the answer
answer
=
type
(
'Answer%s'
%
(
request
.
__name__
,
),
(
Packet
,
),
{})
answer
=
type
(
'Answer%s'
%
(
request
.
__name__
,
),
(
Packet
,
),
{})
answer
.
_fmt
=
request
.
_answer
answer
.
_fmt
=
request
.
_answer
answer
.
poll_thread
=
request
.
poll_thread
# compute the answer code
# compute the answer code
code
=
code
|
RESPONSE_MASK
code
=
code
|
RESPONSE_MASK
answer
.
_request
=
request
answer
.
_request
=
request
...
@@ -1565,7 +1560,7 @@ class ParserState(object):
...
@@ -1565,7 +1560,7 @@ class ParserState(object):
class
Packets
(
dict
):
class
Packets
(
dict
):
"""
"""
Packet registry that check
packet code unicity and provide
an index
Packet registry that check
s packet code uniqueness and provides
an index
"""
"""
def
__metaclass__
(
name
,
base
,
d
):
def
__metaclass__
(
name
,
base
,
d
):
for
k
,
v
in
d
.
iteritems
():
for
k
,
v
in
d
.
iteritems
():
...
@@ -1688,8 +1683,6 @@ class Packets(dict):
...
@@ -1688,8 +1683,6 @@ class Packets(dict):
AddPendingNodes
,
ignore_when_closed
=
False
)
AddPendingNodes
,
ignore_when_closed
=
False
)
TweakPartitionTable
=
register
(
TweakPartitionTable
=
register
(
TweakPartitionTable
,
ignore_when_closed
=
False
)
TweakPartitionTable
,
ignore_when_closed
=
False
)
AskNodeInformation
,
AnswerNodeInformation
=
register
(
NodeInformation
)
SetClusterState
=
register
(
SetClusterState
=
register
(
SetClusterState
,
ignore_when_closed
=
False
)
SetClusterState
,
ignore_when_closed
=
False
)
NotifyClusterInformation
=
register
(
NotifyClusterInformation
=
register
(
...
...
neo/lib/threaded_app.py
View file @
4bedd3fc
...
@@ -43,6 +43,8 @@ class ThreadContainer(threading.local):
...
@@ -43,6 +43,8 @@ class ThreadContainer(threading.local):
class
ThreadedApplication
(
BaseApplication
):
class
ThreadedApplication
(
BaseApplication
):
"""The client node application."""
"""The client node application."""
uuid
=
None
def
__init__
(
self
,
master_nodes
,
name
,
**
kw
):
def
__init__
(
self
,
master_nodes
,
name
,
**
kw
):
super
(
ThreadedApplication
,
self
).
__init__
(
**
kw
)
super
(
ThreadedApplication
,
self
).
__init__
(
**
kw
)
self
.
poll_thread
=
threading
.
Thread
(
target
=
self
.
run
,
name
=
name
)
self
.
poll_thread
=
threading
.
Thread
(
target
=
self
.
run
,
name
=
name
)
...
@@ -56,8 +58,6 @@ class ThreadedApplication(BaseApplication):
...
@@ -56,8 +58,6 @@ class ThreadedApplication(BaseApplication):
for
address
in
master_nodes
:
for
address
in
master_nodes
:
self
.
nm
.
createMaster
(
address
=
address
)
self
.
nm
.
createMaster
(
address
=
address
)
# no self-assigned UUID, primary master will supply us one
self
.
uuid
=
None
# Internal attribute distinct between thread
# Internal attribute distinct between thread
self
.
_thread_container
=
ThreadContainer
()
self
.
_thread_container
=
ThreadContainer
()
app_set
.
add
(
self
)
# to register self.on_log
app_set
.
add
(
self
)
# to register self.on_log
...
@@ -150,7 +150,7 @@ class ThreadedApplication(BaseApplication):
...
@@ -150,7 +150,7 @@ class ThreadedApplication(BaseApplication):
if
msg_id
==
qpacket
.
getId
():
if
msg_id
==
qpacket
.
getId
():
if
is_forgotten
:
if
is_forgotten
:
raise
ValueError
,
'ForgottenPacket for an '
\
raise
ValueError
,
'ForgottenPacket for an '
\
'explicit
e
ly expected packet.'
'explicitly expected packet.'
_handlePacket
(
qconn
,
qpacket
,
kw
,
handler
)
_handlePacket
(
qconn
,
qpacket
,
kw
,
handler
)
break
break
if
not
is_forgotten
and
qpacket
is
not
None
:
if
not
is_forgotten
and
qpacket
is
not
None
:
...
...
neo/lib/util.py
View file @
4bedd3fc
...
@@ -142,7 +142,7 @@ def parseNodeAddress(address, port_opt=None):
...
@@ -142,7 +142,7 @@ def parseNodeAddress(address, port_opt=None):
else
:
else
:
host
=
address
host
=
address
port
=
port_opt
port
=
port_opt
# Resolve (maybe) and cast to can
n
onical form
# Resolve (maybe) and cast to canonical form
# XXX: Always pick the first result. This might not be what is desired, and
# XXX: Always pick the first result. This might not be what is desired, and
# if so this function should either take a hint on the desired address type
# if so this function should either take a hint on the desired address type
# or return either raw host & port or getaddrinfo return value.
# or return either raw host & port or getaddrinfo return value.
...
...
neo/master/app.py
View file @
4bedd3fc
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import
sys
,
weakref
import
sys
,
weakref
from
collections
import
defaultdict
from
time
import
time
from
time
import
time
from
neo.lib
import
logging
from
neo.lib
import
logging
...
@@ -40,11 +41,10 @@ from .verification import VerificationManager
...
@@ -40,11 +41,10 @@ from .verification import VerificationManager
class
Application
(
BaseApplication
):
class
Application
(
BaseApplication
):
"""The master node application."""
"""The master node application."""
packing
=
None
packing
=
None
# Latest completely commited TID
# Latest completely commit
t
ed TID
last_transaction
=
ZERO_TID
last_transaction
=
ZERO_TID
backup_tid
=
None
backup_tid
=
None
backup_app
=
None
backup_app
=
None
uuid
=
None
truncate_tid
=
None
truncate_tid
=
None
def
__init__
(
self
,
config
):
def
__init__
(
self
,
config
):
...
@@ -79,9 +79,7 @@ class Application(BaseApplication):
...
@@ -79,9 +79,7 @@ class Application(BaseApplication):
self
.
primary_master_node
=
None
self
.
primary_master_node
=
None
self
.
cluster_state
=
None
self
.
cluster_state
=
None
uuid
=
config
.
getUUID
()
self
.
uuid
=
config
.
getUUID
()
if
uuid
:
self
.
uuid
=
uuid
# election related data
# election related data
self
.
unconnected_master_node_set
=
set
()
self
.
unconnected_master_node_set
=
set
()
...
@@ -227,19 +225,20 @@ class Application(BaseApplication):
...
@@ -227,19 +225,20 @@ class Application(BaseApplication):
Broadcast changes for a set a nodes
Broadcast changes for a set a nodes
Send only one packet per connection to reduce bandwidth
Send only one packet per connection to reduce bandwidth
"""
"""
node_dict
=
{}
node_dict
=
defaultdict
(
list
)
# group modified nodes by destination node type
# group modified nodes by destination node type
for
node
in
node_list
:
for
node
in
node_list
:
node_info
=
node
.
asTuple
()
node_info
=
node
.
asTuple
()
def
assign_for_notification
(
node_type
):
if
node
.
isAdmin
():
# helper function
continue
node_dict
.
setdefault
(
node_type
,
[]).
append
(
node_info
)
node_dict
[
NodeTypes
.
ADMIN
].
append
(
node_info
)
if
node
.
isMaster
()
or
node
.
isStorage
():
node_dict
[
NodeTypes
.
STORAGE
].
append
(
node_info
)
# client get notifications for master and storage only
if
node
.
isClient
():
assign_for_notification
(
NodeTypes
.
CLIENT
)
continue
if
node
.
isMaster
()
or
node
.
isStorage
()
or
node
.
isClient
():
node_dict
[
NodeTypes
.
CLIENT
].
append
(
node_info
)
assign_for_notification
(
NodeTypes
.
STORAGE
)
if
node
.
isStorage
():
assign_for_notification
(
NodeTypes
.
ADMIN
)
continue
node_dict
[
NodeTypes
.
MASTER
].
append
(
node_info
)
# send at most one non-empty notification packet per node
# send at most one non-empty notification packet per node
for
node
in
self
.
nm
.
getIdentifiedList
():
for
node
in
self
.
nm
.
getIdentifiedList
():
...
@@ -261,7 +260,7 @@ class Application(BaseApplication):
...
@@ -261,7 +260,7 @@ class Application(BaseApplication):
def
provideService
(
self
):
def
provideService
(
self
):
"""
"""
This is the normal mode for a primary master node. Handle transactions
This is the normal mode for a primary master node. Handle transactions
and stop the service only if a catastroph
y
happens or the user commits
and stop the service only if a catastroph
e
happens or the user commits
a shutdown.
a shutdown.
"""
"""
logging
.
info
(
'provide service'
)
logging
.
info
(
'provide service'
)
...
@@ -298,7 +297,7 @@ class Application(BaseApplication):
...
@@ -298,7 +297,7 @@ class Application(BaseApplication):
# secondaries, rather than the other way around. This requires
# secondaries, rather than the other way around. This requires
# a bit more work when a new master joins a cluster but makes
# a bit more work when a new master joins a cluster but makes
# it easier to resolve UUID conflicts with minimal cluster
# it easier to resolve UUID conflicts with minimal cluster
# impact, and ensure primary master uni
city
(primary masters
# impact, and ensure primary master uni
queness
(primary masters
# become noisy, in that they actively try to maintain
# become noisy, in that they actively try to maintain
# connections to all other master nodes, so duplicate
# connections to all other master nodes, so duplicate
# primaries will eventually get in touch with each other and
# primaries will eventually get in touch with each other and
...
@@ -308,6 +307,11 @@ class Application(BaseApplication):
...
@@ -308,6 +307,11 @@ class Application(BaseApplication):
# masters will reconnect nevertheless, but it's dirty.
# masters will reconnect nevertheless, but it's dirty.
# Currently, it's not trivial to preserve connected nodes,
# Currently, it's not trivial to preserve connected nodes,
# because of poor node status tracking during election.
# because of poor node status tracking during election.
# XXX: The above comment is partially wrong in that the primary
# master is now responsible of allocating node ids, and all
# other nodes must only create/update/remove nodes when
# processing node notification. We probably want to keep the
# current behaviour: having only server connections.
conn
.
abort
()
conn
.
abort
()
# If I know any storage node, make sure that they are not in the
# If I know any storage node, make sure that they are not in the
...
@@ -493,7 +497,7 @@ class Application(BaseApplication):
...
@@ -493,7 +497,7 @@ class Application(BaseApplication):
conn
.
setHandler
(
handler
)
conn
.
setHandler
(
handler
)
conn
.
notify
(
Packets
.
NotifyNodeInformation
(((
conn
.
notify
(
Packets
.
NotifyNodeInformation
(((
node
.
getType
(),
node
.
getAddress
(),
node
.
getUUID
(),
node
.
getType
(),
node
.
getAddress
(),
node
.
getUUID
(),
NodeStates
.
TEMPORARILY_DOWN
),)))
NodeStates
.
TEMPORARILY_DOWN
,
None
),)))
conn
.
abort
()
conn
.
abort
()
elif
conn
.
pending
():
elif
conn
.
pending
():
conn
.
abort
()
conn
.
abort
()
...
...
neo/master/backup_app.py
View file @
4bedd3fc
...
@@ -66,6 +66,7 @@ There is no UUID conflict between the 2 clusters:
...
@@ -66,6 +66,7 @@ There is no UUID conflict between the 2 clusters:
class
BackupApplication
(
object
):
class
BackupApplication
(
object
):
pt
=
None
pt
=
None
uuid
=
None
def
__init__
(
self
,
app
,
name
,
master_addresses
):
def
__init__
(
self
,
app
,
name
,
master_addresses
):
self
.
app
=
weakref
.
proxy
(
app
)
self
.
app
=
weakref
.
proxy
(
app
)
...
@@ -93,7 +94,7 @@ class BackupApplication(object):
...
@@ -93,7 +94,7 @@ class BackupApplication(object):
pt
=
app
.
pt
pt
=
app
.
pt
while
True
:
while
True
:
app
.
changeClusterState
(
ClusterStates
.
STARTING_BACKUP
)
app
.
changeClusterState
(
ClusterStates
.
STARTING_BACKUP
)
bootstrap
=
BootstrapManager
(
self
,
self
.
name
,
NodeTypes
.
CLIENT
)
bootstrap
=
BootstrapManager
(
self
,
NodeTypes
.
CLIENT
)
# {offset -> node} (primary storage for off which will be talking to upstream cluster)
# {offset -> node} (primary storage for off which will be talking to upstream cluster)
self
.
primary_partition_dict
=
{}
self
.
primary_partition_dict
=
{}
# [[tid]] part -> []tid↑ (currently scheduled-for-sync txns)
# [[tid]] part -> []tid↑ (currently scheduled-for-sync txns)
...
@@ -106,7 +107,7 @@ class BackupApplication(object):
...
@@ -106,7 +107,7 @@ class BackupApplication(object):
else
:
else
:
break
break
poll
(
1
)
poll
(
1
)
node
,
conn
,
uuid
,
num_partitions
,
num_replicas
=
\
node
,
conn
,
num_partitions
,
num_replicas
=
\
bootstrap
.
getPrimaryConnection
()
bootstrap
.
getPrimaryConnection
()
try
:
try
:
app
.
changeClusterState
(
ClusterStates
.
BACKINGUP
)
app
.
changeClusterState
(
ClusterStates
.
BACKINGUP
)
...
@@ -115,7 +116,6 @@ class BackupApplication(object):
...
@@ -115,7 +116,6 @@ class BackupApplication(object):
raise
RuntimeError
(
"inconsistent number of partitions"
)
raise
RuntimeError
(
"inconsistent number of partitions"
)
self
.
pt
=
PartitionTable
(
num_partitions
,
num_replicas
)
self
.
pt
=
PartitionTable
(
num_partitions
,
num_replicas
)
conn
.
setHandler
(
BackupHandler
(
self
))
conn
.
setHandler
(
BackupHandler
(
self
))
conn
.
ask
(
Packets
.
AskNodeInformation
())
conn
.
ask
(
Packets
.
AskPartitionTable
())
conn
.
ask
(
Packets
.
AskPartitionTable
())
conn
.
ask
(
Packets
.
AskLastTransaction
())
conn
.
ask
(
Packets
.
AskLastTransaction
())
# debug variable to log how big 'tid_list' can be.
# debug variable to log how big 'tid_list' can be.
...
...
neo/master/handlers/__init__.py
View file @
4bedd3fc
...
@@ -18,7 +18,7 @@ from neo.lib import logging
...
@@ -18,7 +18,7 @@ from neo.lib import logging
from
neo.lib.exception
import
StoppedOperation
from
neo.lib.exception
import
StoppedOperation
from
neo.lib.handler
import
EventHandler
from
neo.lib.handler
import
EventHandler
from
neo.lib.protocol
import
(
uuid_str
,
NodeTypes
,
NodeStates
,
Packets
,
from
neo.lib.protocol
import
(
uuid_str
,
NodeTypes
,
NodeStates
,
Packets
,
BrokenNodeDisallowedError
,
BrokenNodeDisallowedError
,
ProtocolError
,
)
)
X
=
0
X
=
0
...
@@ -29,18 +29,19 @@ class MasterHandler(EventHandler):
...
@@ -29,18 +29,19 @@ class MasterHandler(EventHandler):
def
connectionCompleted
(
self
,
conn
,
new
=
None
):
def
connectionCompleted
(
self
,
conn
,
new
=
None
):
if
new
is
None
:
if
new
is
None
:
super
(
MasterHandler
,
self
).
connectionCompleted
(
conn
)
super
(
MasterHandler
,
self
).
connectionCompleted
(
conn
)
elif
new
:
self
.
_notifyNodeInformation
(
conn
)
def
requestIdentification
(
self
,
conn
,
node_type
,
uuid
,
address
,
name
):
def
requestIdentification
(
self
,
conn
,
node_type
,
uuid
,
address
,
name
,
_
):
self
.
checkClusterName
(
name
)
self
.
checkClusterName
(
name
)
app
=
self
.
app
app
=
self
.
app
node
=
app
.
nm
.
getByUUID
(
uuid
)
node
=
app
.
nm
.
getByUUID
(
uuid
)
if
node
:
if
node
:
assert
node_type
is
not
NodeTypes
.
MASTER
or
node
.
getAddress
()
in
(
if
node_type
is
NodeTypes
.
MASTER
and
not
(
address
,
None
),
(
node
,
address
)
None
!=
address
==
node
.
getAddress
()):
raise
ProtocolError
if
node
.
isBroken
():
if
node
.
isBroken
():
raise
BrokenNodeDisallowedError
raise
BrokenNodeDisallowedError
else
:
node
=
app
.
nm
.
getByAddress
(
address
)
peer_uuid
=
self
.
_setupNode
(
conn
,
node_type
,
uuid
,
address
,
node
)
peer_uuid
=
self
.
_setupNode
(
conn
,
node_type
,
uuid
,
address
,
node
)
if
app
.
primary
:
if
app
.
primary
:
primary_address
=
app
.
server
primary_address
=
app
.
server
...
@@ -99,10 +100,6 @@ class MasterHandler(EventHandler):
...
@@ -99,10 +100,6 @@ class MasterHandler(EventHandler):
node_list
.
extend
(
n
.
asTuple
()
for
n
in
nm
.
getStorageList
())
node_list
.
extend
(
n
.
asTuple
()
for
n
in
nm
.
getStorageList
())
conn
.
notify
(
Packets
.
NotifyNodeInformation
(
node_list
))
conn
.
notify
(
Packets
.
NotifyNodeInformation
(
node_list
))
def
askNodeInformation
(
self
,
conn
):
self
.
_notifyNodeInformation
(
conn
)
conn
.
answer
(
Packets
.
AnswerNodeInformation
())
def
askPartitionTable
(
self
,
conn
):
def
askPartitionTable
(
self
,
conn
):
pt
=
self
.
app
.
pt
pt
=
self
.
app
.
pt
conn
.
answer
(
Packets
.
AnswerPartitionTable
(
pt
.
getID
(),
pt
.
getRowList
()))
conn
.
answer
(
Packets
.
AnswerPartitionTable
(
pt
.
getID
(),
pt
.
getRowList
()))
...
...
neo/master/handlers/backup.py
View file @
4bedd3fc
...
@@ -31,12 +31,6 @@ class BackupHandler(EventHandler):
...
@@ -31,12 +31,6 @@ class BackupHandler(EventHandler):
def
notifyPartitionChanges
(
self
,
conn
,
ptid
,
cell_list
):
def
notifyPartitionChanges
(
self
,
conn
,
ptid
,
cell_list
):
self
.
app
.
pt
.
update
(
ptid
,
cell_list
,
self
.
app
.
nm
)
self
.
app
.
pt
.
update
(
ptid
,
cell_list
,
self
.
app
.
nm
)
def
answerNodeInformation
(
self
,
conn
):
pass
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
self
.
app
.
nm
.
update
(
node_list
)
# NOTE invalidation from M -> Mb (all partitions)
# NOTE invalidation from M -> Mb (all partitions)
def
answerLastTransaction
(
self
,
conn
,
tid
):
def
answerLastTransaction
(
self
,
conn
,
tid
):
app
=
self
.
app
app
=
self
.
app
...
...
neo/master/handlers/client.py
View file @
4bedd3fc
...
@@ -31,14 +31,12 @@ class ClientServiceHandler(MasterHandler):
...
@@ -31,14 +31,12 @@ class ClientServiceHandler(MasterHandler):
app
.
broadcastNodesInformation
([
node
])
app
.
broadcastNodesInformation
([
node
])
app
.
nm
.
remove
(
node
)
app
.
nm
.
remove
(
node
)
def
askNodeInformation
(
self
,
conn
):
def
_notifyNodeInformation
(
self
,
conn
):
# send informations about master and storages only
nm
=
self
.
app
.
nm
nm
=
self
.
app
.
nm
node_list
=
[
]
node_list
=
[
nm
.
getByUUID
(
conn
.
getUUID
()).
asTuple
()]
# for id_timestamp
node_list
.
extend
(
n
.
asTuple
()
for
n
in
nm
.
getMasterList
())
node_list
.
extend
(
n
.
asTuple
()
for
n
in
nm
.
getMasterList
())
node_list
.
extend
(
n
.
asTuple
()
for
n
in
nm
.
getStorageList
())
node_list
.
extend
(
n
.
asTuple
()
for
n
in
nm
.
getStorageList
())
conn
.
notify
(
Packets
.
NotifyNodeInformation
(
node_list
))
conn
.
notify
(
Packets
.
NotifyNodeInformation
(
node_list
))
conn
.
answer
(
Packets
.
AnswerNodeInformation
())
def
askBeginTransaction
(
self
,
conn
,
tid
):
def
askBeginTransaction
(
self
,
conn
,
tid
):
"""
"""
...
...
neo/master/handlers/election.py
View file @
4bedd3fc
...
@@ -23,6 +23,9 @@ from . import MasterHandler
...
@@ -23,6 +23,9 @@ from . import MasterHandler
class
BaseElectionHandler
(
EventHandler
):
class
BaseElectionHandler
(
EventHandler
):
def
_notifyNodeInformation
(
self
,
conn
):
pass
def
reelectPrimary
(
self
,
conn
):
def
reelectPrimary
(
self
,
conn
):
raise
ElectionFailure
,
'reelection requested'
raise
ElectionFailure
,
'reelection requested'
...
@@ -53,6 +56,11 @@ class BaseElectionHandler(EventHandler):
...
@@ -53,6 +56,11 @@ class BaseElectionHandler(EventHandler):
class
ClientElectionHandler
(
BaseElectionHandler
):
class
ClientElectionHandler
(
BaseElectionHandler
):
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
# XXX: For the moment, do nothing because
# we'll close this connection and reconnect.
pass
def
connectionFailed
(
self
,
conn
):
def
connectionFailed
(
self
,
conn
):
addr
=
conn
.
getAddress
()
addr
=
conn
.
getAddress
()
node
=
self
.
app
.
nm
.
getByAddress
(
addr
)
node
=
self
.
app
.
nm
.
getByAddress
(
addr
)
...
@@ -68,6 +76,7 @@ class ClientElectionHandler(BaseElectionHandler):
...
@@ -68,6 +76,7 @@ class ClientElectionHandler(BaseElectionHandler):
app
.
uuid
,
app
.
uuid
,
app
.
server
,
app
.
server
,
app
.
name
,
app
.
name
,
None
,
))
))
super
(
ClientElectionHandler
,
self
).
connectionCompleted
(
conn
)
super
(
ClientElectionHandler
,
self
).
connectionCompleted
(
conn
)
...
@@ -126,8 +135,8 @@ class ServerElectionHandler(BaseElectionHandler, MasterHandler):
...
@@ -126,8 +135,8 @@ class ServerElectionHandler(BaseElectionHandler, MasterHandler):
logging
.
info
(
'reject a connection from a non-master'
)
logging
.
info
(
'reject a connection from a non-master'
)
raise
NotReadyError
raise
NotReadyError
if
node
is
None
:
if
node
is
None
is
app
.
nm
.
getByAddress
(
address
)
:
node
=
app
.
nm
.
createMaster
(
address
=
address
)
app
.
nm
.
createMaster
(
address
=
address
)
self
.
elect
(
conn
,
address
)
self
.
elect
(
conn
,
address
)
return
uuid
return
uuid
...
...
neo/master/handlers/identification.py
View file @
4bedd3fc
...
@@ -14,6 +14,7 @@
...
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from
time
import
time
from
neo.lib
import
logging
from
neo.lib
import
logging
from
neo.lib.protocol
import
ClusterStates
,
NodeStates
,
NodeTypes
,
\
from
neo.lib.protocol
import
ClusterStates
,
NodeStates
,
NodeTypes
,
\
NotReadyError
,
ProtocolError
,
uuid_str
NotReadyError
,
ProtocolError
,
uuid_str
...
@@ -30,14 +31,32 @@ class IdentificationHandler(MasterHandler):
...
@@ -30,14 +31,32 @@ class IdentificationHandler(MasterHandler):
def
_setupNode
(
self
,
conn
,
node_type
,
uuid
,
address
,
node
):
def
_setupNode
(
self
,
conn
,
node_type
,
uuid
,
address
,
node
):
app
=
self
.
app
app
=
self
.
app
if
node
:
by_addr
=
address
and
app
.
nm
.
getByAddress
(
address
)
if
node
.
isRunning
():
while
1
:
# cloned/evil/buggy node connecting to us
if
by_addr
:
raise
ProtocolError
(
'already connected'
)
if
not
by_addr
.
isConnected
():
if
node
is
by_addr
:
break
if
not
node
or
uuid
<
0
:
# In case of address conflict for a peer with temporary
# ids, we'll generate a new id.
node
=
by_addr
break
elif
node
:
if
node
.
isConnected
():
if
uuid
<
0
:
# The peer wants a temporary id that's already assigned.
# Let's give it another one.
node
=
uuid
=
None
break
else
:
else
:
assert
not
node
.
isConnected
()
node
.
setAddress
(
address
)
node
.
setAddress
(
address
)
node
.
setRunning
()
break
# Id conflict for a storage node.
else
:
break
# cloned/evil/buggy node connecting to us
raise
ProtocolError
(
'already connected'
)
state
=
NodeStates
.
RUNNING
state
=
NodeStates
.
RUNNING
if
node_type
==
NodeTypes
.
CLIENT
:
if
node_type
==
NodeTypes
.
CLIENT
:
...
@@ -64,14 +83,16 @@ class IdentificationHandler(MasterHandler):
...
@@ -64,14 +83,16 @@ class IdentificationHandler(MasterHandler):
handler
=
app
.
administration_handler
handler
=
app
.
administration_handler
human_readable_node_type
=
'n admin '
human_readable_node_type
=
'n admin '
else
:
else
:
raise
NotImplementedError
(
node_type
)
raise
ProtocolError
uuid
=
app
.
getNewUUID
(
uuid
,
address
,
node_type
)
uuid
=
app
.
getNewUUID
(
uuid
,
address
,
node_type
)
logging
.
info
(
'Accept a'
+
human_readable_node_type
+
uuid_str
(
uuid
))
logging
.
info
(
'Accept a'
+
human_readable_node_type
+
uuid_str
(
uuid
))
if
node
is
None
:
if
node
is
None
:
node
=
app
.
nm
.
createFromNodeType
(
node_type
,
node
=
app
.
nm
.
createFromNodeType
(
node_type
,
uuid
=
uuid
,
address
=
address
)
uuid
=
uuid
,
address
=
address
)
else
:
node
.
setUUID
(
uuid
)
node
.
setUUID
(
uuid
)
node
.
id_timestamp
=
time
()
node
.
setState
(
state
)
node
.
setState
(
state
)
node
.
setConnection
(
conn
)
node
.
setConnection
(
conn
)
conn
.
setHandler
(
handler
)
conn
.
setHandler
(
handler
)
...
...
neo/master/handlers/secondary.py
View file @
4bedd3fc
...
@@ -36,6 +36,10 @@ class SecondaryMasterHandler(MasterHandler):
...
@@ -36,6 +36,10 @@ class SecondaryMasterHandler(MasterHandler):
def
reelectPrimary
(
self
,
conn
):
def
reelectPrimary
(
self
,
conn
):
raise
ElectionFailure
,
'reelection requested'
raise
ElectionFailure
,
'reelection requested'
def
_notifyNodeInformation
(
self
,
conn
):
node_list
=
[
n
.
asTuple
()
for
n
in
self
.
app
.
nm
.
getMasterList
()]
conn
.
notify
(
Packets
.
NotifyNodeInformation
(
node_list
))
class
PrimaryHandler
(
EventHandler
):
class
PrimaryHandler
(
EventHandler
):
""" Handler used by secondaries to handle primary master"""
""" Handler used by secondaries to handle primary master"""
...
@@ -51,13 +55,14 @@ class PrimaryHandler(EventHandler):
...
@@ -51,13 +55,14 @@ class PrimaryHandler(EventHandler):
app
=
self
.
app
app
=
self
.
app
addr
=
conn
.
getAddress
()
addr
=
conn
.
getAddress
()
node
=
app
.
nm
.
getByAddress
(
addr
)
node
=
app
.
nm
.
getByAddress
(
addr
)
# connection successful
l
, set it as running
# connection successful, set it as running
node
.
setRunning
()
node
.
setRunning
()
conn
.
ask
(
Packets
.
RequestIdentification
(
conn
.
ask
(
Packets
.
RequestIdentification
(
NodeTypes
.
MASTER
,
NodeTypes
.
MASTER
,
app
.
uuid
,
app
.
uuid
,
app
.
server
,
app
.
server
,
app
.
name
,
app
.
name
,
None
,
))
))
super
(
PrimaryHandler
,
self
).
connectionCompleted
(
conn
)
super
(
PrimaryHandler
,
self
).
connectionCompleted
(
conn
)
...
@@ -68,27 +73,11 @@ class PrimaryHandler(EventHandler):
...
@@ -68,27 +73,11 @@ class PrimaryHandler(EventHandler):
self
.
app
.
cluster_state
=
state
self
.
app
.
cluster_state
=
state
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
app
=
self
.
app
super
(
PrimaryHandler
,
self
).
notifyNodeInformation
(
conn
,
node_list
)
for
node_type
,
addr
,
uuid
,
state
in
node_list
:
for
node_type
,
_
,
uuid
,
state
,
_
in
node_list
:
if
node_type
!=
NodeTypes
.
MASTER
:
assert
node_type
==
NodeTypes
.
MASTER
,
node_type
# No interest.
if
uuid
==
self
.
app
.
uuid
and
state
==
NodeStates
.
UNKNOWN
:
continue
if
uuid
==
app
.
uuid
and
state
==
NodeStates
.
UNKNOWN
:
sys
.
exit
()
sys
.
exit
()
# Register new master nodes.
if
app
.
server
==
addr
:
# This is self.
continue
else
:
n
=
app
.
nm
.
getByAddress
(
addr
)
# master node must be known
assert
n
is
not
None
if
uuid
is
not
None
:
# If I don't know the UUID yet, believe what the peer
# told me at the moment.
if
n
.
getUUID
()
is
None
:
n
.
setUUID
(
uuid
)
def
_acceptIdentification
(
self
,
node
,
uuid
,
num_partitions
,
def
_acceptIdentification
(
self
,
node
,
uuid
,
num_partitions
,
num_replicas
,
your_uuid
,
primary
,
known_master_list
):
num_replicas
,
your_uuid
,
primary
,
known_master_list
):
...
@@ -101,4 +90,5 @@ class PrimaryHandler(EventHandler):
...
@@ -101,4 +90,5 @@ class PrimaryHandler(EventHandler):
logging
.
info
(
'My UUID: '
+
uuid_str
(
your_uuid
))
logging
.
info
(
'My UUID: '
+
uuid_str
(
your_uuid
))
node
.
setUUID
(
uuid
)
node
.
setUUID
(
uuid
)
app
.
id_timestamp
=
None
neo/master/handlers/storage.py
View file @
4bedd3fc
...
@@ -27,13 +27,11 @@ class StorageServiceHandler(BaseServiceHandler):
...
@@ -27,13 +27,11 @@ class StorageServiceHandler(BaseServiceHandler):
def
connectionCompleted
(
self
,
conn
,
new
):
def
connectionCompleted
(
self
,
conn
,
new
):
app
=
self
.
app
app
=
self
.
app
uuid
=
conn
.
getUUID
()
uuid
=
conn
.
getUUID
()
node
=
app
.
nm
.
getByUUID
(
uuid
)
app
.
setStorageNotReady
(
uuid
)
app
.
setStorageNotReady
(
uuid
)
if
new
:
if
new
:
super
(
StorageServiceHandler
,
self
).
connectionCompleted
(
conn
,
new
)
super
(
StorageServiceHandler
,
self
).
connectionCompleted
(
conn
,
new
)
# XXX: what other values could happen ?
if
app
.
nm
.
getByUUID
(
uuid
).
isRunning
():
# node may be PENDING
if
node
.
isRunning
():
conn
.
notify
(
Packets
.
StartOperation
(
app
.
backup_tid
))
conn
.
notify
(
Packets
.
StartOperation
(
bool
(
app
.
backup_tid
)))
def
connectionLost
(
self
,
conn
,
new_state
):
def
connectionLost
(
self
,
conn
,
new_state
):
app
=
self
.
app
app
=
self
.
app
...
@@ -85,7 +83,7 @@ class StorageServiceHandler(BaseServiceHandler):
...
@@ -85,7 +83,7 @@ class StorageServiceHandler(BaseServiceHandler):
try
:
try
:
cell_list
=
self
.
app
.
pt
.
setUpToDate
(
node
,
offset
)
cell_list
=
self
.
app
.
pt
.
setUpToDate
(
node
,
offset
)
if
not
cell_list
:
if
not
cell_list
:
raise
ProtocolError
(
'Non-oudated partition'
)
raise
ProtocolError
(
'Non-ou
t
dated partition'
)
except
PartitionTableException
,
e
:
except
PartitionTableException
,
e
:
raise
ProtocolError
(
str
(
e
))
raise
ProtocolError
(
str
(
e
))
logging
.
debug
(
"%s is up for offset %s"
,
node
,
offset
)
logging
.
debug
(
"%s is up for offset %s"
,
node
,
offset
)
...
...
neo/master/transactions.py
View file @
4bedd3fc
...
@@ -334,7 +334,7 @@ class TransactionManager(object):
...
@@ -334,7 +334,7 @@ class TransactionManager(object):
"""
"""
Set that a node has locked the transaction.
Set that a node has locked the transaction.
If transaction is completely locked, calls function given at
If transaction is completely locked, calls function given at
instan
c
iation time.
instan
t
iation time.
"""
"""
logging
.
debug
(
'Lock TXN %s for %s'
,
dump
(
ttid
),
uuid_str
(
uuid
))
logging
.
debug
(
'Lock TXN %s for %s'
,
dump
(
ttid
),
uuid_str
(
uuid
))
if
self
[
ttid
].
lock
(
uuid
)
and
self
.
_queue
[
0
]
==
ttid
:
if
self
[
ttid
].
lock
(
uuid
)
and
self
.
_queue
[
0
]
==
ttid
:
...
...
neo/neoctl/app.py
View file @
4bedd3fc
...
@@ -174,7 +174,7 @@ class TerminalNeoCTL(object):
...
@@ -174,7 +174,7 @@ class TerminalNeoCTL(object):
def
tweakPartitionTable
(
self
,
params
):
def
tweakPartitionTable
(
self
,
params
):
"""
"""
Optimize partition table.
Optimize partition table.
No partiti
ti
on will be assigned to specified storage nodes.
No partition will be assigned to specified storage nodes.
Parameters: [node [...]]
Parameters: [node [...]]
"""
"""
return
self
.
neoctl
.
tweakPartitionTable
(
map
(
self
.
asNode
,
params
))
return
self
.
neoctl
.
tweakPartitionTable
(
map
(
self
.
asNode
,
params
))
...
@@ -294,7 +294,7 @@ class Application(object):
...
@@ -294,7 +294,7 @@ class Application(object):
if
docstring
is
None
:
if
docstring
is
None
:
docstring
=
'(no docstring)'
docstring
=
'(no docstring)'
docstring_line_list
=
docstring
.
split
(
'
\
n
'
)
docstring_line_list
=
docstring
.
split
(
'
\
n
'
)
# Strip empty lines at begining & end of line list
# Strip empty lines at begin
n
ing & end of line list
for
end
in
(
0
,
-
1
):
for
end
in
(
0
,
-
1
):
while
len
(
docstring_line_list
)
\
while
len
(
docstring_line_list
)
\
and
docstring_line_list
[
end
]
==
''
:
and
docstring_line_list
[
end
]
==
''
:
...
...
neo/scripts/neolog.py
View file @
4bedd3fc
...
@@ -146,15 +146,14 @@ class Log(object):
...
@@ -146,15 +146,14 @@ class Log(object):
def
notifyNodeInformation
(
self
,
node_list
):
def
notifyNodeInformation
(
self
,
node_list
):
node_list
.
sort
(
key
=
lambda
x
:
x
[
2
])
node_list
.
sort
(
key
=
lambda
x
:
x
[
2
])
node_list
=
[(
self
.
uuid_str
(
uuid
),
str
(
node_type
),
node_list
=
[(
self
.
uuid_str
(
x
[
2
]),
str
(
x
[
0
]),
'%s:%u'
%
address
if
address
else
'?'
,
state
)
'%s:%u'
%
x
[
1
]
if
x
[
1
]
else
'?'
,
str
(
x
[
3
]))
for
node_type
,
address
,
uuid
,
state
in
node_list
]
+
((
repr
(
x
[
4
]),)
if
len
(
x
)
>
4
else
())
# BBB
for
x
in
node_list
]
if
node_list
:
if
node_list
:
t
=
' ! %%%us | %%%us | %%%us | %%s'
%
(
t
=
''
.
join
(
' %%%us |'
%
max
(
len
(
x
[
i
])
for
x
in
node_list
)
max
(
len
(
x
[
0
])
for
x
in
node_list
),
for
i
in
xrange
(
len
(
node_list
[
0
])
-
1
))
max
(
len
(
x
[
1
])
for
x
in
node_list
),
return
map
((
' !'
+
t
+
' %s'
).
__mod__
,
node_list
)
max
(
len
(
x
[
2
])
for
x
in
node_list
))
return
map
(
t
.
__mod__
,
node_list
)
return
()
return
()
...
...
neo/scripts/neostorage.py
View file @
4bedd3fc
...
@@ -43,7 +43,7 @@ def main(args=None):
...
@@ -43,7 +43,7 @@ def main(args=None):
# TODO: Forbid using "reset" along with any unneeded argument.
# TODO: Forbid using "reset" along with any unneeded argument.
# "reset" is too dangerous to let user a chance of accidentally
# "reset" is too dangerous to let user a chance of accidentally
# letting it slip through in a long option list.
# letting it slip through in a long option list.
# We should drop support configation files to make such check useful.
# We should drop support config
ur
ation files to make such check useful.
(
options
,
args
)
=
parser
.
parse_args
(
args
=
args
)
(
options
,
args
)
=
parser
.
parse_args
(
args
=
args
)
config
=
ConfigurationManager
(
defaults
,
options
,
'storage'
)
config
=
ConfigurationManager
(
defaults
,
options
,
'storage'
)
...
...
neo/scripts/runner.py
View file @
4bedd3fc
...
@@ -29,11 +29,7 @@ from unittest.runner import _WritelnDecorator
...
@@ -29,11 +29,7 @@ from unittest.runner import _WritelnDecorator
if
filter
(
re
.
compile
(
r'--coverage$|-\
w*c
').match, sys.argv[1:]):
if
filter
(
re
.
compile
(
r'--coverage$|-\
w*c
').match, sys.argv[1:]):
# Start coverage as soon as possible.
# Start coverage as soon as possible.
import coverage
import coverage
coverage = coverage.Coverage(source=('
neo
',), omit=(
coverage = coverage.Coverage()
'
neo
/
debug
.
py
',
'
neo
/
scripts
/
runner
.
py
',
'
neo
/
tests
/*
',
))
coverage.start()
coverage.start()
import neo
import neo
...
...
neo/storage/app.py
View file @
4bedd3fc
...
@@ -219,14 +219,11 @@ class Application(BaseApplication):
...
@@ -219,14 +219,11 @@ class Application(BaseApplication):
conn
.
close
()
conn
.
close
()
# search, find, connect and identify to the primary master
# search, find, connect and identify to the primary master
bootstrap
=
BootstrapManager
(
self
,
self
.
name
,
bootstrap
=
BootstrapManager
(
self
,
NodeTypes
.
STORAGE
,
self
.
server
)
NodeTypes
.
STORAGE
,
self
.
uuid
,
self
.
server
)
self
.
master_node
,
self
.
master_conn
,
num_partitions
,
num_replicas
=
\
data
=
bootstrap
.
getPrimaryConnection
()
bootstrap
.
getPrimaryConnection
()
(
node
,
conn
,
uuid
,
num_partitions
,
num_replicas
)
=
data
uuid
=
self
.
uuid
self
.
master_node
=
node
self
.
master_conn
=
conn
logging
.
info
(
'I am %s'
,
uuid_str
(
uuid
))
logging
.
info
(
'I am %s'
,
uuid_str
(
uuid
))
self
.
uuid
=
uuid
self
.
dm
.
setUUID
(
uuid
)
self
.
dm
.
setUUID
(
uuid
)
# Reload a partition table from the database. This is necessary
# Reload a partition table from the database. This is necessary
...
...
neo/storage/checker.py
View file @
4bedd3fc
...
@@ -50,8 +50,8 @@ class Checker(object):
...
@@ -50,8 +50,8 @@ class Checker(object):
conn
.
asClient
()
conn
.
asClient
()
else
:
else
:
conn
=
ClientConnection
(
app
,
StorageOperationHandler
(
app
),
node
)
conn
=
ClientConnection
(
app
,
StorageOperationHandler
(
app
),
node
)
conn
.
ask
(
Packets
.
RequestIdentification
(
conn
.
ask
(
Packets
.
RequestIdentification
(
NodeTypes
.
STORAGE
,
NodeTypes
.
STORAGE
,
uuid
,
app
.
server
,
name
))
uuid
,
app
.
server
,
name
,
app
.
id_timestamp
))
self
.
conn_dict
[
conn
]
=
node
.
isIdentified
()
self
.
conn_dict
[
conn
]
=
node
.
isIdentified
()
conn_set
=
set
(
self
.
conn_dict
)
conn_set
=
set
(
self
.
conn_dict
)
conn_set
.
discard
(
None
)
conn_set
.
discard
(
None
)
...
...
neo/storage/database/manager.py
View file @
4bedd3fc
...
@@ -78,7 +78,7 @@ class DatabaseManager(object):
...
@@ -78,7 +78,7 @@ class DatabaseManager(object):
@
abstract
@
abstract
def
_parse
(
self
,
database
):
def
_parse
(
self
,
database
):
"""Called during instan
c
iation, to process database parameter."""
"""Called during instan
t
iation, to process database parameter."""
def
setup
(
self
,
reset
=
0
):
def
setup
(
self
,
reset
=
0
):
"""Set up a database, discarding existing data first if reset is True
"""Set up a database, discarding existing data first if reset is True
...
@@ -94,7 +94,7 @@ class DatabaseManager(object):
...
@@ -94,7 +94,7 @@ class DatabaseManager(object):
@
abstract
@
abstract
def
_setup
(
self
):
def
_setup
(
self
):
"""To be overriden by the backend to set up a database
"""To be overrid
d
en by the backend to set up a database
It must recover self._uncommitted_data from temporary object table.
It must recover self._uncommitted_data from temporary object table.
_uncommitted_data is already instantiated and must be updated with
_uncommitted_data is already instantiated and must be updated with
...
@@ -417,7 +417,7 @@ class DatabaseManager(object):
...
@@ -417,7 +417,7 @@ class DatabaseManager(object):
@
abstract
@
abstract
def
_pruneData
(
self
,
data_id_list
):
def
_pruneData
(
self
,
data_id_list
):
"""To be overriden by the backend to delete any unreferenced data
"""To be overrid
d
en by the backend to delete any unreferenced data
'unreferenced' means:
'unreferenced' means:
- not in self._uncommitted_data
- not in self._uncommitted_data
...
@@ -427,7 +427,7 @@ class DatabaseManager(object):
...
@@ -427,7 +427,7 @@ class DatabaseManager(object):
@
abstract
@
abstract
def
storeData
(
self
,
checksum
,
data
,
compression
):
def
storeData
(
self
,
checksum
,
data
,
compression
):
"""To be overriden by the backend to store object raw data
"""To be overrid
d
en by the backend to store object raw data
If same data was already stored, the storage only has to check there's
If same data was already stored, the storage only has to check there's
no hash collision.
no hash collision.
...
@@ -491,7 +491,7 @@ class DatabaseManager(object):
...
@@ -491,7 +491,7 @@ class DatabaseManager(object):
tid
tid
Transation doing the undo
Transation doing the undo
ltid
ltid
Upper (exclued) bound of transactions visible to transaction doing
Upper (exclu
d
ed) bound of transactions visible to transaction doing
the undo.
the undo.
undone_tid
undone_tid
Transaction to undo
Transaction to undo
...
@@ -643,7 +643,7 @@ class DatabaseManager(object):
...
@@ -643,7 +643,7 @@ class DatabaseManager(object):
@
abstract
@
abstract
def
checkTIDRange
(
self
,
partition
,
length
,
min_tid
,
max_tid
):
def
checkTIDRange
(
self
,
partition
,
length
,
min_tid
,
max_tid
):
"""
"""
Generate a dig
g
est from transaction list.
Generate a digest from transaction list.
min_tid (packed)
min_tid (packed)
TID at which verification starts.
TID at which verification starts.
length (int)
length (int)
...
@@ -660,7 +660,7 @@ class DatabaseManager(object):
...
@@ -660,7 +660,7 @@ class DatabaseManager(object):
@
abstract
@
abstract
def
checkSerialRange
(
self
,
partition
,
length
,
min_tid
,
max_tid
,
min_oid
):
def
checkSerialRange
(
self
,
partition
,
length
,
min_tid
,
max_tid
,
min_oid
):
"""
"""
Generate a dig
g
est from object list.
Generate a digest from object list.
min_oid (packed)
min_oid (packed)
OID at which verification starts.
OID at which verification starts.
min_tid (packed)
min_tid (packed)
...
...
neo/storage/database/mysqldb.py
View file @
4bedd3fc
...
@@ -216,7 +216,7 @@ class MySQLDatabaseManager(DatabaseManager):
...
@@ -216,7 +216,7 @@ class MySQLDatabaseManager(DatabaseManager):
engine
+=
" compression='tokudb_uncompressed'"
engine
+=
" compression='tokudb_uncompressed'"
# The table "data" stores object data.
# The table "data" stores object data.
# We'd like to have partial index on 'hash' colum (e.g. hash(4))
# We'd like to have partial index on 'hash' colum
n
(e.g. hash(4))
# but 'UNIQUE' constraint would not work as expected.
# but 'UNIQUE' constraint would not work as expected.
q
(
"""CREATE TABLE IF NOT EXISTS data (
q
(
"""CREATE TABLE IF NOT EXISTS data (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
...
@@ -634,7 +634,7 @@ class MySQLDatabaseManager(DatabaseManager):
...
@@ -634,7 +634,7 @@ class MySQLDatabaseManager(DatabaseManager):
return
oid_list
,
user
,
desc
,
ext
,
bool
(
packed
),
util
.
p64
(
ttid
)
return
oid_list
,
user
,
desc
,
ext
,
bool
(
packed
),
util
.
p64
(
ttid
)
def
getObjectHistory
(
self
,
oid
,
offset
,
length
):
def
getObjectHistory
(
self
,
oid
,
offset
,
length
):
# FIXME: This method doesn't take client's current ransaction id as
# FIXME: This method doesn't take client's current
t
ransaction id as
# parameter, which means it can return transactions in the future of
# parameter, which means it can return transactions in the future of
# client's transaction.
# client's transaction.
oid
=
util
.
u64
(
oid
)
oid
=
util
.
u64
(
oid
)
...
...
neo/storage/handlers/__init__.py
View file @
4bedd3fc
...
@@ -38,8 +38,8 @@ class BaseMasterHandler(EventHandler):
...
@@ -38,8 +38,8 @@ class BaseMasterHandler(EventHandler):
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
"""Store information on nodes, only if this is sent by a primary
"""Store information on nodes, only if this is sent by a primary
master node."""
master node."""
s
elf
.
app
.
nm
.
update
(
node_list
)
s
uper
(
BaseMasterHandler
,
self
).
notifyNodeInformation
(
conn
,
node_list
)
for
node_type
,
addr
,
uuid
,
state
in
node_list
:
for
node_type
,
_
,
uuid
,
state
,
_
in
node_list
:
if
uuid
==
self
.
app
.
uuid
:
if
uuid
==
self
.
app
.
uuid
:
# This is me, do what the master tell me
# This is me, do what the master tell me
logging
.
info
(
"I was told I'm %s"
,
state
)
logging
.
info
(
"I was told I'm %s"
,
state
)
...
...
neo/storage/handlers/client.py
View file @
4bedd3fc
...
@@ -58,13 +58,6 @@ class ClientOperationHandler(EventHandler):
...
@@ -58,13 +58,6 @@ class ClientOperationHandler(EventHandler):
compression
,
checksum
,
data
,
data_serial
)
compression
,
checksum
,
data
,
data_serial
)
conn
.
answer
(
p
)
conn
.
answer
(
p
)
def
connectionLost
(
self
,
conn
,
new_state
):
uuid
=
conn
.
getUUID
()
node
=
self
.
app
.
nm
.
getByUUID
(
uuid
)
if
self
.
app
.
listening_conn
:
# if running
assert
node
is
not
None
,
conn
self
.
app
.
nm
.
remove
(
node
)
def
abortTransaction
(
self
,
conn
,
ttid
):
def
abortTransaction
(
self
,
conn
,
ttid
):
self
.
app
.
tm
.
abort
(
ttid
)
self
.
app
.
tm
.
abort
(
ttid
)
...
@@ -88,7 +81,7 @@ class ClientOperationHandler(EventHandler):
...
@@ -88,7 +81,7 @@ class ClientOperationHandler(EventHandler):
except
DelayedError
:
except
DelayedError
:
# locked by a previous transaction, retry later
# locked by a previous transaction, retry later
# If we are unlocking, we want queueEvent to raise
# If we are unlocking, we want queueEvent to raise
# AlreadyPendingError, to avoid making
lc
ient wait for an unneeded
# AlreadyPendingError, to avoid making
cl
ient wait for an unneeded
# response.
# response.
try
:
try
:
self
.
app
.
queueEvent
(
self
.
_askStoreObject
,
conn
,
(
oid
,
serial
,
self
.
app
.
queueEvent
(
self
.
_askStoreObject
,
conn
,
(
oid
,
serial
,
...
...
neo/storage/handlers/identification.py
View file @
4bedd3fc
...
@@ -27,13 +27,13 @@ class IdentificationHandler(EventHandler):
...
@@ -27,13 +27,13 @@ class IdentificationHandler(EventHandler):
def
connectionLost
(
self
,
conn
,
new_state
):
def
connectionLost
(
self
,
conn
,
new_state
):
logging
.
warning
(
'A connection was lost during identification'
)
logging
.
warning
(
'A connection was lost during identification'
)
def
requestIdentification
(
self
,
conn
,
node_type
,
def
requestIdentification
(
self
,
conn
,
node_type
,
uuid
,
address
,
name
,
uuid
,
address
,
name
):
id_timestamp
):
self
.
checkClusterName
(
name
)
self
.
checkClusterName
(
name
)
app
=
self
.
app
# reject any incoming connections if not ready
# reject any incoming connections if not ready
if
not
self
.
app
.
ready
:
if
not
app
.
ready
:
raise
NotReadyError
raise
NotReadyError
app
=
self
.
app
if
uuid
is
None
:
if
uuid
is
None
:
if
node_type
!=
NodeTypes
.
STORAGE
:
if
node_type
!=
NodeTypes
.
STORAGE
:
raise
ProtocolError
(
'reject anonymous non-storage node'
)
raise
ProtocolError
(
'reject anonymous non-storage node'
)
...
@@ -42,9 +42,14 @@ class IdentificationHandler(EventHandler):
...
@@ -42,9 +42,14 @@ class IdentificationHandler(EventHandler):
else
:
else
:
if
uuid
==
app
.
uuid
:
if
uuid
==
app
.
uuid
:
raise
ProtocolError
(
"uuid conflict or loopback connection"
)
raise
ProtocolError
(
"uuid conflict or loopback connection"
)
node
=
app
.
nm
.
getByUUID
(
uuid
)
node
=
app
.
nm
.
getByUUID
(
uuid
,
id_timestamp
)
# If this node is broken, reject it.
if
node
is
None
:
if
node
is
not
None
and
node
.
isBroken
():
# Do never create node automatically, or we could get id
# conflicts. We must only rely on the notifications from the
# master to recognize nodes. So this is not always an error:
# maybe there are incoming notifications.
raise
NotReadyError
(
'unknown node: retry later'
)
if
node
.
isBroken
():
raise
BrokenNodeDisallowedError
raise
BrokenNodeDisallowedError
# choose the handler according to the node type
# choose the handler according to the node type
if
node_type
==
NodeTypes
.
CLIENT
:
if
node_type
==
NodeTypes
.
CLIENT
:
...
@@ -52,20 +57,9 @@ class IdentificationHandler(EventHandler):
...
@@ -52,20 +57,9 @@ class IdentificationHandler(EventHandler):
handler
=
ClientReadOnlyOperationHandler
handler
=
ClientReadOnlyOperationHandler
else
:
else
:
handler
=
ClientOperationHandler
handler
=
ClientOperationHandler
if
node
is
None
:
assert
not
node
.
isConnected
(),
node
node
=
app
.
nm
.
createClient
(
uuid
=
uuid
)
assert
node
.
isRunning
(),
node
elif
node
.
isConnected
():
# This can happen if we haven't processed yet a notification
# from the master, telling us the existing node is not
# running anymore. If we accept the new client, we won't
# know what to do with this late notification.
raise
NotReadyError
(
'uuid conflict: retry later'
)
node
.
setRunning
()
elif
node_type
==
NodeTypes
.
STORAGE
:
elif
node_type
==
NodeTypes
.
STORAGE
:
if
node
is
None
:
logging
.
error
(
'reject an unknown storage node %s'
,
uuid_str
(
uuid
))
raise
NotReadyError
handler
=
StorageOperationHandler
handler
=
StorageOperationHandler
else
:
else
:
raise
ProtocolError
(
'reject non-client-or-storage node'
)
raise
ProtocolError
(
'reject non-client-or-storage node'
)
...
...
neo/storage/handlers/initialization.py
View file @
4bedd3fc
...
@@ -20,16 +20,13 @@ from neo.lib.protocol import Packets, ProtocolError, ZERO_TID
...
@@ -20,16 +20,13 @@ from neo.lib.protocol import Packets, ProtocolError, ZERO_TID
class
InitializationHandler
(
BaseMasterHandler
):
class
InitializationHandler
(
BaseMasterHandler
):
def
answerNodeInformation
(
self
,
conn
):
pass
def
sendPartitionTable
(
self
,
conn
,
ptid
,
row_list
):
def
sendPartitionTable
(
self
,
conn
,
ptid
,
row_list
):
app
=
self
.
app
app
=
self
.
app
pt
=
app
.
pt
pt
=
app
.
pt
pt
.
load
(
ptid
,
row_list
,
self
.
app
.
nm
)
pt
.
load
(
ptid
,
row_list
,
self
.
app
.
nm
)
if
not
pt
.
filled
():
if
not
pt
.
filled
():
raise
ProtocolError
(
'Partial partition table received'
)
raise
ProtocolError
(
'Partial partition table received'
)
# Install the partition table into the database for persistenc
y
.
# Install the partition table into the database for persistenc
e
.
cell_list
=
[]
cell_list
=
[]
num_partitions
=
pt
.
getPartitions
()
num_partitions
=
pt
.
getPartitions
()
unassigned_set
=
set
(
xrange
(
num_partitions
))
unassigned_set
=
set
(
xrange
(
num_partitions
))
...
...
neo/storage/replicator.py
View file @
4bedd3fc
...
@@ -258,7 +258,8 @@ class Replicator(object):
...
@@ -258,7 +258,8 @@ class Replicator(object):
conn
=
ClientConnection
(
app
,
StorageOperationHandler
(
app
),
node
)
conn
=
ClientConnection
(
app
,
StorageOperationHandler
(
app
),
node
)
try
:
try
:
conn
.
ask
(
Packets
.
RequestIdentification
(
NodeTypes
.
STORAGE
,
conn
.
ask
(
Packets
.
RequestIdentification
(
NodeTypes
.
STORAGE
,
None
if
name
else
app
.
uuid
,
app
.
server
,
name
or
app
.
name
))
None
if
name
else
app
.
uuid
,
app
.
server
,
name
or
app
.
name
,
app
.
id_timestamp
))
except
ConnectionClosed
:
except
ConnectionClosed
:
if
previous_node
is
self
.
current_node
:
if
previous_node
is
self
.
current_node
:
return
return
...
@@ -336,7 +337,7 @@ class Replicator(object):
...
@@ -336,7 +337,7 @@ class Replicator(object):
offset
,
message
and
' (%s)'
%
message
)
offset
,
message
and
' (%s)'
%
message
)
if
offset
in
self
.
partition_dict
:
if
offset
in
self
.
partition_dict
:
# XXX: Try another partition if possible, to increase probability to
# XXX: Try another partition if possible, to increase probability to
# connect to another node. It would be better to explicit
e
ly
# connect to another node. It would be better to explicitly
# search for another node instead.
# search for another node instead.
tid
=
self
.
replicate_dict
.
pop
(
offset
,
None
)
or
self
.
replicate_tid
tid
=
self
.
replicate_dict
.
pop
(
offset
,
None
)
or
self
.
replicate_tid
if
self
.
replicate_dict
:
if
self
.
replicate_dict
:
...
...
neo/tests/__init__.py
View file @
4bedd3fc
...
@@ -32,6 +32,7 @@ from functools import wraps
...
@@ -32,6 +32,7 @@ from functools import wraps
from
mock
import
Mock
from
mock
import
Mock
from
neo.lib
import
debug
,
logging
,
protocol
from
neo.lib
import
debug
,
logging
,
protocol
from
neo.lib.protocol
import
NodeTypes
,
Packets
,
UUID_NAMESPACES
from
neo.lib.protocol
import
NodeTypes
,
Packets
,
UUID_NAMESPACES
from
neo.lib.util
import
cached_property
from
time
import
time
from
time
import
time
from
struct
import
pack
,
unpack
from
struct
import
pack
,
unpack
from
unittest.case
import
_ExpectedFailure
,
_UnexpectedSuccess
from
unittest.case
import
_ExpectedFailure
,
_UnexpectedSuccess
...
@@ -194,6 +195,15 @@ class NeoUnitTestBase(NeoTestBase):
...
@@ -194,6 +195,15 @@ class NeoUnitTestBase(NeoTestBase):
self
.
uuid_dict
=
{}
self
.
uuid_dict
=
{}
NeoTestBase
.
setUp
(
self
)
NeoTestBase
.
setUp
(
self
)
@
cached_property
def
nm
(
self
):
from
neo.lib
import
node
return
node
.
NodeManager
()
def
createStorage
(
self
,
*
args
):
return
self
.
nm
.
createStorage
(
**
dict
(
zip
(
(
'address'
,
'uuid'
,
'state'
),
args
)))
def
prepareDatabase
(
self
,
number
,
prefix
=
DB_PREFIX
):
def
prepareDatabase
(
self
,
number
,
prefix
=
DB_PREFIX
):
""" create empty databases """
""" create empty databases """
adapter
=
os
.
getenv
(
'NEO_TESTS_ADAPTER'
,
'MySQL'
)
adapter
=
os
.
getenv
(
'NEO_TESTS_ADAPTER'
,
'MySQL'
)
...
@@ -312,7 +322,7 @@ class NeoUnitTestBase(NeoTestBase):
...
@@ -312,7 +322,7 @@ class NeoUnitTestBase(NeoTestBase):
self
.
assertRaises
(
protocol
.
ProtocolError
,
method
,
*
args
,
**
kwargs
)
self
.
assertRaises
(
protocol
.
ProtocolError
,
method
,
*
args
,
**
kwargs
)
def
checkUnexpectedPacketRaised
(
self
,
method
,
*
args
,
**
kwargs
):
def
checkUnexpectedPacketRaised
(
self
,
method
,
*
args
,
**
kwargs
):
""" Check if the UnexpectedPacketError exception w
x
as raised """
""" Check if the UnexpectedPacketError exception was raised """
self
.
assertRaises
(
protocol
.
UnexpectedPacketError
,
method
,
*
args
,
**
kwargs
)
self
.
assertRaises
(
protocol
.
UnexpectedPacketError
,
method
,
*
args
,
**
kwargs
)
def
checkIdenficationRequired
(
self
,
method
,
*
args
,
**
kwargs
):
def
checkIdenficationRequired
(
self
,
method
,
*
args
,
**
kwargs
):
...
@@ -320,11 +330,11 @@ class NeoUnitTestBase(NeoTestBase):
...
@@ -320,11 +330,11 @@ class NeoUnitTestBase(NeoTestBase):
self
.
checkUnexpectedPacketRaised
(
method
,
*
args
,
**
kwargs
)
self
.
checkUnexpectedPacketRaised
(
method
,
*
args
,
**
kwargs
)
def
checkBrokenNodeDisallowedErrorRaised
(
self
,
method
,
*
args
,
**
kwargs
):
def
checkBrokenNodeDisallowedErrorRaised
(
self
,
method
,
*
args
,
**
kwargs
):
""" Check if the BrokenNodeDisallowedError exception w
x
as raised """
""" Check if the BrokenNodeDisallowedError exception was raised """
self
.
assertRaises
(
protocol
.
BrokenNodeDisallowedError
,
method
,
*
args
,
**
kwargs
)
self
.
assertRaises
(
protocol
.
BrokenNodeDisallowedError
,
method
,
*
args
,
**
kwargs
)
def
checkNotReadyErrorRaised
(
self
,
method
,
*
args
,
**
kwargs
):
def
checkNotReadyErrorRaised
(
self
,
method
,
*
args
,
**
kwargs
):
""" Check if the NotReadyError exception w
x
as raised """
""" Check if the NotReadyError exception was raised """
self
.
assertRaises
(
protocol
.
NotReadyError
,
method
,
*
args
,
**
kwargs
)
self
.
assertRaises
(
protocol
.
NotReadyError
,
method
,
*
args
,
**
kwargs
)
def
checkAborted
(
self
,
conn
):
def
checkAborted
(
self
,
conn
):
...
@@ -372,7 +382,7 @@ class NeoUnitTestBase(NeoTestBase):
...
@@ -372,7 +382,7 @@ class NeoUnitTestBase(NeoTestBase):
self
.
assertEqual
(
found_uuid
,
uuid
)
self
.
assertEqual
(
found_uuid
,
uuid
)
# in check(Ask|Answer|Notify)Packet we return the packet so it can be used
# in check(Ask|Answer|Notify)Packet we return the packet so it can be used
# in tests if more accurate
s
checks are required
# in tests if more accurate checks are required
def
checkErrorPacket
(
self
,
conn
,
decode
=
False
):
def
checkErrorPacket
(
self
,
conn
,
decode
=
False
):
""" Check if an error packet was answered """
""" Check if an error packet was answered """
...
...
neo/tests/client/testClientApp.py
View file @
4bedd3fc
...
@@ -81,7 +81,7 @@ class ClientApplicationTests(NeoUnitTestBase):
...
@@ -81,7 +81,7 @@ class ClientApplicationTests(NeoUnitTestBase):
# stop threads
# stop threads
for
app
in
self
.
_to_stop_list
:
for
app
in
self
.
_to_stop_list
:
app
.
close
()
app
.
close
()
# restore environ
ne
ment
# restore environment
Application
.
_ask
=
self
.
_ask
Application
.
_ask
=
self
.
_ask
Application
.
_getMasterConnection
=
self
.
_getMasterConnection
Application
.
_getMasterConnection
=
self
.
_getMasterConnection
NeoUnitTestBase
.
_tearDown
(
self
,
success
)
NeoUnitTestBase
.
_tearDown
(
self
,
success
)
...
@@ -596,7 +596,7 @@ class ClientApplicationTests(NeoUnitTestBase):
...
@@ -596,7 +596,7 @@ class ClientApplicationTests(NeoUnitTestBase):
Object oid previous revision before tid1 is tid0.
Object oid previous revision before tid1 is tid0.
Transaction tid2 modified oid (and contains its data).
Transaction tid2 modified oid (and contains its data).
Undo is rejeced with a raise, because conflict resolution fails.
Undo is rejec
t
ed with a raise, because conflict resolution fails.
"""
"""
oid0
=
self
.
makeOID
(
1
)
oid0
=
self
.
makeOID
(
1
)
tid0
=
self
.
getNextTID
()
tid0
=
self
.
getNextTID
()
...
@@ -753,11 +753,7 @@ class ClientApplicationTests(NeoUnitTestBase):
...
@@ -753,11 +753,7 @@ class ClientApplicationTests(NeoUnitTestBase):
# will raise IndexError at the third iteration
# will raise IndexError at the third iteration
app
=
self
.
getApp
(
'127.0.0.1:10010 127.0.0.1:10011'
)
app
=
self
.
getApp
(
'127.0.0.1:10010 127.0.0.1:10011'
)
# TODO: test more connection failure cases
# TODO: test more connection failure cases
all_passed
=
[]
# askLastTransaction
# askLastTransaction
def
_ask9
(
_
):
all_passed
.
append
(
1
)
# Seventh packet : askNodeInformation succeeded
def
_ask8
(
_
):
def
_ask8
(
_
):
pass
pass
# Sixth packet : askPartitionTable succeeded
# Sixth packet : askPartitionTable succeeded
...
@@ -789,19 +785,18 @@ class ClientApplicationTests(NeoUnitTestBase):
...
@@ -789,19 +785,18 @@ class ClientApplicationTests(NeoUnitTestBase):
# telling us what its address is.)
# telling us what its address is.)
def
_ask1
(
_
):
def
_ask1
(
_
):
pass
pass
ask_func_list
=
[
_ask1
,
_ask2
,
_ask3
,
_ask4
,
_ask6
,
_ask7
,
ask_func_list
=
[
_ask1
,
_ask2
,
_ask3
,
_ask4
,
_ask6
,
_ask7
,
_ask8
]
_ask8
,
_ask9
]
def
_ask_base
(
conn
,
_
,
handler
=
None
):
def
_ask_base
(
conn
,
_
,
handler
=
None
):
ask_func_list
.
pop
(
0
)(
conn
)
ask_func_list
.
pop
(
0
)(
conn
)
app
.
nm
.
getByAddress
(
conn
.
getAddress
()).
_connection
=
None
app
.
nm
.
getByAddress
(
conn
.
getAddress
()).
_connection
=
None
app
.
_ask
=
_ask_base
app
.
_ask
=
_ask_base
# fake
d environne
ment
# fake
environ
ment
app
.
em
.
close
()
app
.
em
.
close
()
app
.
em
=
Mock
({
'getConnectionList'
:
[]})
app
.
em
=
Mock
({
'getConnectionList'
:
[]})
app
.
pt
=
Mock
({
'operational'
:
False
})
app
.
pt
=
Mock
({
'operational'
:
False
})
app
.
start
=
lambda
:
None
app
.
start
=
lambda
:
None
app
.
master_conn
=
app
.
_connectToPrimaryNode
()
app
.
master_conn
=
app
.
_connectToPrimaryNode
()
self
.
assert
Equal
(
len
(
all_passed
),
1
)
self
.
assert
False
(
ask_func_list
)
self
.
assertTrue
(
app
.
master_conn
is
not
None
)
self
.
assertTrue
(
app
.
master_conn
is
not
None
)
self
.
assertTrue
(
app
.
pt
.
operational
())
self
.
assertTrue
(
app
.
pt
.
operational
())
...
@@ -831,11 +826,11 @@ class ClientApplicationTests(NeoUnitTestBase):
...
@@ -831,11 +826,11 @@ class ClientApplicationTests(NeoUnitTestBase):
self
.
assertTrue
(
self
.
test_ok
)
self
.
assertTrue
(
self
.
test_ok
)
# check NEOStorageError is raised when the primary connection is lost
# check NEOStorageError is raised when the primary connection is lost
app
.
master_conn
=
None
app
.
master_conn
=
None
# check disabled since we reonnect to pmn
# check disabled since we re
c
onnect to pmn
#self.assertRaises(NEOStorageError, app._askPrimary, packet)
#self.assertRaises(NEOStorageError, app._askPrimary, packet)
def
test_threadContextIsolation
(
self
):
def
test_threadContextIsolation
(
self
):
""" Thread context properties must not be visible ac
c
ross instances
""" Thread context properties must not be visible across instances
while remaining in the same thread """
while remaining in the same thread """
app1
=
self
.
getApp
()
app1
=
self
.
getApp
()
app1_local
=
app1
.
_thread_container
app1_local
=
app1
.
_thread_container
...
...
neo/tests/client/testMasterHandler.py
View file @
4bedd3fc
...
@@ -44,69 +44,6 @@ class MasterHandlerTests(NeoUnitTestBase):
...
@@ -44,69 +44,6 @@ class MasterHandlerTests(NeoUnitTestBase):
node
.
setConnection
(
conn
)
node
.
setConnection
(
conn
)
return
node
,
conn
return
node
,
conn
class
MasterBootstrapHandlerTests
(
MasterHandlerTests
):
def
setUp
(
self
):
super
(
MasterBootstrapHandlerTests
,
self
).
setUp
()
self
.
handler
=
PrimaryBootstrapHandler
(
self
.
app
)
def
checkCalledOnApp
(
self
,
method
,
index
=
0
):
calls
=
self
.
app
.
mockGetNamedCalls
(
method
)
self
.
assertTrue
(
len
(
calls
)
>
index
)
return
calls
[
index
].
params
def
test_notReady
(
self
):
conn
=
self
.
getFakeConnection
()
self
.
handler
.
notReady
(
conn
,
'message'
)
self
.
assertEqual
(
self
.
app
.
trying_master_node
,
None
)
def
test_acceptIdentification1
(
self
):
""" Non-master node """
node
,
conn
=
self
.
getKnownMaster
()
self
.
handler
.
acceptIdentification
(
conn
,
NodeTypes
.
CLIENT
,
node
.
getUUID
(),
100
,
0
,
None
,
None
,
[])
self
.
checkClosed
(
conn
)
def
test_acceptIdentification2
(
self
):
""" No UUID supplied """
node
,
conn
=
self
.
getKnownMaster
()
uuid
=
self
.
getMasterUUID
()
addr
=
conn
.
getAddress
()
self
.
checkProtocolErrorRaised
(
self
.
handler
.
acceptIdentification
,
conn
,
NodeTypes
.
MASTER
,
uuid
,
100
,
0
,
None
,
addr
,
[(
addr
,
uuid
)],
)
def
test_acceptIdentification3
(
self
):
""" identification accepted """
node
,
conn
=
self
.
getKnownMaster
()
uuid
=
self
.
getMasterUUID
()
addr
=
conn
.
getAddress
()
your_uuid
=
self
.
getClientUUID
()
self
.
handler
.
acceptIdentification
(
conn
,
NodeTypes
.
MASTER
,
uuid
,
100
,
2
,
your_uuid
,
addr
,
[(
addr
,
uuid
)])
self
.
assertEqual
(
self
.
app
.
uuid
,
your_uuid
)
self
.
assertEqual
(
node
.
getUUID
(),
uuid
)
self
.
assertTrue
(
isinstance
(
self
.
app
.
pt
,
PartitionTable
))
def
_getMasterList
(
self
,
uuid_list
):
port
=
1000
master_list
=
[]
for
uuid
in
uuid_list
:
master_list
.
append
(((
'127.0.0.1'
,
port
),
uuid
))
port
+=
1
return
master_list
def
test_answerPartitionTable
(
self
):
conn
=
self
.
getFakeConnection
()
self
.
app
.
pt
=
Mock
()
ptid
=
0
row_list
=
([],
[])
self
.
handler
.
answerPartitionTable
(
conn
,
ptid
,
row_list
)
load_calls
=
self
.
app
.
pt
.
mockGetNamedCalls
(
'load'
)
self
.
assertEqual
(
len
(
load_calls
),
1
)
# load_calls[0].checkArgs(ptid, row_list, self.app.nm)
class
MasterNotificationsHandlerTests
(
MasterHandlerTests
):
class
MasterNotificationsHandlerTests
(
MasterHandlerTests
):
...
...
neo/tests/functional/__init__.py
View file @
4bedd3fc
...
@@ -119,7 +119,7 @@ class NEOProcess(object):
...
@@ -119,7 +119,7 @@ class NEOProcess(object):
except
ImportError
:
except
ImportError
:
raise
NotFound
,
'%s not found'
%
(
command
)
raise
NotFound
,
'%s not found'
%
(
command
)
self
.
command
=
command
self
.
command
=
command
self
.
arg_dict
=
{
'--'
+
k
:
v
for
k
,
v
in
arg_dict
.
iteritems
()}
self
.
arg_dict
=
arg_dict
self
.
with_uuid
=
True
self
.
with_uuid
=
True
self
.
setUUID
(
uuid
)
self
.
setUUID
(
uuid
)
...
@@ -131,11 +131,11 @@ class NEOProcess(object):
...
@@ -131,11 +131,11 @@ class NEOProcess(object):
args
=
[]
args
=
[]
self
.
with_uuid
=
with_uuid
self
.
with_uuid
=
with_uuid
for
arg
,
param
in
self
.
arg_dict
.
iteritems
():
for
arg
,
param
in
self
.
arg_dict
.
iteritems
():
if
with_uuid
is
False
and
arg
==
'--uuid'
:
args
.
append
(
'--'
+
arg
)
continue
args
.
append
(
arg
)
if
param
is
not
None
:
if
param
is
not
None
:
args
.
append
(
str
(
param
))
args
.
append
(
str
(
param
))
if
with_uuid
:
args
+=
'--uuid'
,
str
(
self
.
uuid
)
self
.
pid
=
os
.
fork
()
self
.
pid
=
os
.
fork
()
if
self
.
pid
==
0
:
if
self
.
pid
==
0
:
# Child
# Child
...
@@ -183,7 +183,7 @@ class NEOProcess(object):
...
@@ -183,7 +183,7 @@ class NEOProcess(object):
self
.
wait
()
self
.
wait
()
except
:
except
:
# We can ignore all exceptions at this point, since there is no
# We can ignore all exceptions at this point, since there is no
# garanteed way to handle them (other objects we would depend on
# g
u
aranteed way to handle them (other objects we would depend on
# might already have been deleted).
# might already have been deleted).
pass
pass
...
@@ -213,7 +213,6 @@ class NEOProcess(object):
...
@@ -213,7 +213,6 @@ class NEOProcess(object):
Note: for this change to take effect, the node must be restarted.
Note: for this change to take effect, the node must be restarted.
"""
"""
self
.
uuid
=
uuid
self
.
uuid
=
uuid
self
.
arg_dict
[
'--uuid'
]
=
str
(
uuid
)
def
isAlive
(
self
):
def
isAlive
(
self
):
try
:
try
:
...
@@ -305,7 +304,6 @@ class NEOCluster(object):
...
@@ -305,7 +304,6 @@ class NEOCluster(object):
def
_newProcess
(
self
,
node_type
,
logfile
=
None
,
port
=
None
,
**
kw
):
def
_newProcess
(
self
,
node_type
,
logfile
=
None
,
port
=
None
,
**
kw
):
self
.
uuid_dict
[
node_type
]
=
uuid
=
1
+
self
.
uuid_dict
.
get
(
node_type
,
0
)
self
.
uuid_dict
[
node_type
]
=
uuid
=
1
+
self
.
uuid_dict
.
get
(
node_type
,
0
)
uuid
+=
UUID_NAMESPACES
[
node_type
]
<<
24
uuid
+=
UUID_NAMESPACES
[
node_type
]
<<
24
kw
[
'uuid'
]
=
uuid
kw
[
'cluster'
]
=
self
.
cluster_name
kw
[
'cluster'
]
=
self
.
cluster_name
kw
[
'masters'
]
=
self
.
master_nodes
kw
[
'masters'
]
=
self
.
master_nodes
if
logfile
:
if
logfile
:
...
@@ -491,13 +489,9 @@ class NEOCluster(object):
...
@@ -491,13 +489,9 @@ class NEOCluster(object):
return
self
.
__getNodeList
(
NodeTypes
.
CLIENT
,
state
)
return
self
.
__getNodeList
(
NodeTypes
.
CLIENT
,
state
)
def
__getNodeState
(
self
,
node_type
,
uuid
):
def
__getNodeState
(
self
,
node_type
,
uuid
):
node_list
=
self
.
__getNodeList
(
node_type
)
for
node
in
self
.
__getNodeList
(
node_type
):
for
node_type
,
address
,
node_uuid
,
state
in
node_list
:
if
node
[
2
]
==
uuid
:
if
node_uuid
==
uuid
:
return
node
[
3
]
break
else
:
state
=
None
return
state
def
getMasterNodeState
(
self
,
uuid
):
def
getMasterNodeState
(
self
,
uuid
):
return
self
.
__getNodeState
(
NodeTypes
.
MASTER
,
uuid
)
return
self
.
__getNodeState
(
NodeTypes
.
MASTER
,
uuid
)
...
@@ -573,7 +567,7 @@ class NEOCluster(object):
...
@@ -573,7 +567,7 @@ class NEOCluster(object):
def
callback
(
last_try
):
def
callback
(
last_try
):
current_try
=
self
.
getPrimary
()
current_try
=
self
.
getPrimary
()
if
None
not
in
(
uuid
,
current_try
)
and
uuid
!=
current_try
:
if
None
not
in
(
uuid
,
current_try
)
and
uuid
!=
current_try
:
raise
AssertionError
,
'An unexpected primary ar
ised
: %r, '
\
raise
AssertionError
,
'An unexpected primary ar
ose
: %r, '
\
'expected %r'
%
(
dump
(
current_try
),
dump
(
uuid
))
'expected %r'
%
(
dump
(
current_try
),
dump
(
uuid
))
return
uuid
is
None
or
uuid
==
current_try
,
current_try
return
uuid
is
None
or
uuid
==
current_try
,
current_try
self
.
expectCondition
(
callback
,
*
args
,
**
kw
)
self
.
expectCondition
(
callback
,
*
args
,
**
kw
)
...
@@ -581,12 +575,12 @@ class NEOCluster(object):
...
@@ -581,12 +575,12 @@ class NEOCluster(object):
def
expectOudatedCells
(
self
,
number
,
*
args
,
**
kw
):
def
expectOudatedCells
(
self
,
number
,
*
args
,
**
kw
):
def
callback
(
last_try
):
def
callback
(
last_try
):
row_list
=
self
.
neoctl
.
getPartitionRowList
()[
1
]
row_list
=
self
.
neoctl
.
getPartitionRowList
()[
1
]
number_of_oudated
=
0
number_of_ou
t
dated
=
0
for
row
in
row_list
:
for
row
in
row_list
:
for
cell
in
row
[
1
]:
for
cell
in
row
[
1
]:
if
cell
[
1
]
==
CellStates
.
OUT_OF_DATE
:
if
cell
[
1
]
==
CellStates
.
OUT_OF_DATE
:
number_of_oudated
+=
1
number_of_ou
t
dated
+=
1
return
number_of_ou
dated
==
number
,
number_of_ou
dated
return
number_of_ou
tdated
==
number
,
number_of_out
dated
self
.
expectCondition
(
callback
,
*
args
,
**
kw
)
self
.
expectCondition
(
callback
,
*
args
,
**
kw
)
def
expectAssignedCells
(
self
,
process
,
number
,
*
args
,
**
kw
):
def
expectAssignedCells
(
self
,
process
,
number
,
*
args
,
**
kw
):
...
...
neo/tests/functional/testClient.py
View file @
4bedd3fc
...
@@ -43,7 +43,7 @@ class Tree(Persistent):
...
@@ -43,7 +43,7 @@ class Tree(Persistent):
self
.
left
=
Tree
(
depth
)
self
.
left
=
Tree
(
depth
)
# simple persitent object with conflict resolution
# simple persi
s
tent object with conflict resolution
class
PCounter
(
Persistent
):
class
PCounter
(
Persistent
):
_value
=
0
_value
=
0
...
@@ -131,7 +131,7 @@ class ClientTests(NEOFunctionalTest):
...
@@ -131,7 +131,7 @@ class ClientTests(NEOFunctionalTest):
c2
.
root
()[
'other'
]
c2
.
root
()[
'other'
]
c1
.
root
()[
'item'
]
=
1
c1
.
root
()[
'item'
]
=
1
t1
.
commit
()
t1
.
commit
()
# load objet from zope cache
# load obje
c
t from zope cache
self
.
assertEqual
(
c1
.
root
()[
'item'
],
1
)
self
.
assertEqual
(
c1
.
root
()[
'item'
],
1
)
self
.
assertEqual
(
c2
.
root
()[
'item'
],
0
)
self
.
assertEqual
(
c2
.
root
()[
'item'
],
0
)
...
@@ -334,7 +334,7 @@ class ClientTests(NEOFunctionalTest):
...
@@ -334,7 +334,7 @@ class ClientTests(NEOFunctionalTest):
t3
.
user
=
'user'
t3
.
user
=
'user'
t3
.
description
=
'desc'
t3
.
description
=
'desc'
st3
.
tpc_begin
(
t3
)
st3
.
tpc_begin
(
t3
)
# retr
ei
ve the last revision
# retr
ie
ve the last revision
data
,
serial
=
st3
.
load
(
oid
)
data
,
serial
=
st3
.
load
(
oid
)
# try to store again, should not be delayed
# try to store again, should not be delayed
st3
.
store
(
oid
,
serial
,
data
,
''
,
t3
)
st3
.
store
(
oid
,
serial
,
data
,
''
,
t3
)
...
...
neo/tests/functional/testMaster.py
View file @
4bedd3fc
...
@@ -63,7 +63,7 @@ class MasterTests(NEOFunctionalTest):
...
@@ -63,7 +63,7 @@ class MasterTests(NEOFunctionalTest):
# BUG: The following check expects neoctl to reconnect before
# BUG: The following check expects neoctl to reconnect before
# the election finishes.
# the election finishes.
self
.
assertEqual
(
self
.
neo
.
getPrimary
(),
None
)
self
.
assertEqual
(
self
.
neo
.
getPrimary
(),
None
)
# Check that a primary master ar
ised
.
# Check that a primary master ar
ose
.
self
.
neo
.
expectPrimary
(
timeout
=
10
)
self
.
neo
.
expectPrimary
(
timeout
=
10
)
# Check that the uuid really changed.
# Check that the uuid really changed.
new_uuid
=
self
.
neo
.
getPrimary
()
new_uuid
=
self
.
neo
.
getPrimary
()
...
@@ -83,7 +83,7 @@ class MasterTests(NEOFunctionalTest):
...
@@ -83,7 +83,7 @@ class MasterTests(NEOFunctionalTest):
uuid
,
=
self
.
neo
.
killPrimary
()
uuid
,
=
self
.
neo
.
killPrimary
()
# Check the state of the primary we just killed
# Check the state of the primary we just killed
self
.
neo
.
expectMasterState
(
uuid
,
(
None
,
NodeStates
.
UNKNOWN
))
self
.
neo
.
expectMasterState
(
uuid
,
(
None
,
NodeStates
.
UNKNOWN
))
# Check that a primary master ar
ised
.
# Check that a primary master ar
ose
.
self
.
neo
.
expectPrimary
(
timeout
=
10
)
self
.
neo
.
expectPrimary
(
timeout
=
10
)
# Check that the uuid really changed.
# Check that the uuid really changed.
self
.
assertNotEqual
(
self
.
neo
.
getPrimary
(),
uuid
)
self
.
assertNotEqual
(
self
.
neo
.
getPrimary
(),
uuid
)
...
...
neo/tests/functional/testStorage.py
View file @
4bedd3fc
...
@@ -69,7 +69,7 @@ class StorageTests(NEOFunctionalTest):
...
@@ -69,7 +69,7 @@ class StorageTests(NEOFunctionalTest):
def
__checkDatabase
(
self
,
db_name
):
def
__checkDatabase
(
self
,
db_name
):
db
=
self
.
neo
.
getSQLConnection
(
db_name
)
db
=
self
.
neo
.
getSQLConnection
(
db_name
)
# wait for the sql transaction to be commited
# wait for the sql transaction to be commit
t
ed
def
callback
(
last_try
):
def
callback
(
last_try
):
db
.
commit
()
# to get a fresh view
db
.
commit
()
# to get a fresh view
# One revision per object and two for the root, before and after
# One revision per object and two for the root, before and after
...
@@ -157,7 +157,7 @@ class StorageTests(NEOFunctionalTest):
...
@@ -157,7 +157,7 @@ class StorageTests(NEOFunctionalTest):
self
.
neo
.
expectClusterRunning
()
self
.
neo
.
expectClusterRunning
()
def
testOudatedCellsOnDownStorage
(
self
):
def
testOudatedCellsOnDownStorage
(
self
):
""" Check that the storage cells are set as oudated when the node is
""" Check that the storage cells are set as ou
t
dated when the node is
down, the cluster remains up since there is a replica """
down, the cluster remains up since there is a replica """
# populate the two storages
# populate the two storages
...
@@ -185,7 +185,7 @@ class StorageTests(NEOFunctionalTest):
...
@@ -185,7 +185,7 @@ class StorageTests(NEOFunctionalTest):
def
testVerificationTriggered
(
self
):
def
testVerificationTriggered
(
self
):
""" Check that the verification stage is executed when a storage node
""" Check that the verification stage is executed when a storage node
required to be operation
n
al is lost, and the cluster come back in
required to be operational is lost, and the cluster come back in
running state when the storage is up again """
running state when the storage is up again """
# start neo with one storages
# start neo with one storages
...
@@ -444,7 +444,7 @@ class StorageTests(NEOFunctionalTest):
...
@@ -444,7 +444,7 @@ class StorageTests(NEOFunctionalTest):
st
.
tpc_begin
(
t
)
st
.
tpc_begin
(
t
)
st
.
store
(
oid
,
rev
,
data
,
''
,
t
)
st
.
store
(
oid
,
rev
,
data
,
''
,
t
)
# start the oudated storage
# start the ou
t
dated storage
stopped
[
0
].
start
()
stopped
[
0
].
start
()
self
.
neo
.
expectPending
(
stopped
[
0
])
self
.
neo
.
expectPending
(
stopped
[
0
])
self
.
neo
.
neoctl
.
enableStorageList
([
stopped
[
0
].
getUUID
()])
self
.
neo
.
neoctl
.
enableStorageList
([
stopped
[
0
].
getUUID
()])
...
...
neo/tests/master/testClientHandler.py
View file @
4bedd3fc
...
@@ -108,10 +108,12 @@ class MasterClientHandlerTests(NeoUnitTestBase):
...
@@ -108,10 +108,12 @@ class MasterClientHandlerTests(NeoUnitTestBase):
# do the right job
# do the right job
client_uuid
=
self
.
identifyToMasterNode
(
node_type
=
NodeTypes
.
CLIENT
,
port
=
self
.
client_port
)
client_uuid
=
self
.
identifyToMasterNode
(
node_type
=
NodeTypes
.
CLIENT
,
port
=
self
.
client_port
)
storage_uuid
=
self
.
storage_uuid
storage_uuid
=
self
.
storage_uuid
storage_conn
=
self
.
getFakeConnection
(
storage_uuid
,
self
.
storage_address
)
storage_conn
=
self
.
getFakeConnection
(
storage_uuid
,
self
.
storage_address
,
is_server
=
True
)
storage2_uuid
=
self
.
identifyToMasterNode
(
port
=
10022
)
storage2_uuid
=
self
.
identifyToMasterNode
(
port
=
10022
)
storage2_conn
=
self
.
getFakeConnection
(
storage2_uuid
,
storage2_conn
=
self
.
getFakeConnection
(
storage2_uuid
,
(
self
.
storage_address
[
0
],
self
.
storage_address
[
1
]
+
1
))
(
self
.
storage_address
[
0
],
self
.
storage_address
[
1
]
+
1
),
is_server
=
True
)
self
.
app
.
setStorageReady
(
storage2_uuid
)
self
.
app
.
setStorageReady
(
storage2_uuid
)
conn
=
self
.
getFakeConnection
(
client_uuid
,
self
.
client_address
)
conn
=
self
.
getFakeConnection
(
client_uuid
,
self
.
client_address
)
self
.
app
.
pt
=
Mock
({
self
.
app
.
pt
=
Mock
({
...
@@ -142,18 +144,6 @@ class MasterClientHandlerTests(NeoUnitTestBase):
...
@@ -142,18 +144,6 @@ class MasterClientHandlerTests(NeoUnitTestBase):
self
.
assertEqual
(
len
(
txn
.
getOIDList
()),
0
)
self
.
assertEqual
(
len
(
txn
.
getOIDList
()),
0
)
self
.
assertEqual
(
len
(
txn
.
getUUIDList
()),
1
)
self
.
assertEqual
(
len
(
txn
.
getUUIDList
()),
1
)
def
test_askNodeInformations
(
self
):
# check that only informations about master and storages nodes are
# send to a client
self
.
app
.
nm
.
createClient
()
conn
=
self
.
getFakeConnection
()
self
.
service
.
askNodeInformation
(
conn
)
calls
=
conn
.
mockGetNamedCalls
(
'notify'
)
self
.
assertEqual
(
len
(
calls
),
1
)
packet
=
calls
[
0
].
getParam
(
0
)
(
node_list
,
)
=
packet
.
decode
()
self
.
assertEqual
(
len
(
node_list
),
2
)
def
test_connectionClosed
(
self
):
def
test_connectionClosed
(
self
):
# give a client uuid which have unfinished transactions
# give a client uuid which have unfinished transactions
client_uuid
=
self
.
identifyToMasterNode
(
node_type
=
NodeTypes
.
CLIENT
,
client_uuid
=
self
.
identifyToMasterNode
(
node_type
=
NodeTypes
.
CLIENT
,
...
@@ -176,7 +166,7 @@ class MasterClientHandlerTests(NeoUnitTestBase):
...
@@ -176,7 +166,7 @@ class MasterClientHandlerTests(NeoUnitTestBase):
conn
=
self
.
getFakeConnection
(
peer_id
=
peer_id
)
conn
=
self
.
getFakeConnection
(
peer_id
=
peer_id
)
storage_uuid
=
self
.
storage_uuid
storage_uuid
=
self
.
storage_uuid
storage_conn
=
self
.
getFakeConnection
(
storage_uuid
,
storage_conn
=
self
.
getFakeConnection
(
storage_uuid
,
self
.
storage_address
)
self
.
storage_address
,
is_server
=
True
)
self
.
app
.
nm
.
getByUUID
(
storage_uuid
).
setConnection
(
storage_conn
)
self
.
app
.
nm
.
getByUUID
(
storage_uuid
).
setConnection
(
storage_conn
)
self
.
service
.
askPack
(
conn
,
tid
)
self
.
service
.
askPack
(
conn
,
tid
)
self
.
checkNoPacketSent
(
conn
)
self
.
checkNoPacketSent
(
conn
)
...
@@ -189,7 +179,7 @@ class MasterClientHandlerTests(NeoUnitTestBase):
...
@@ -189,7 +179,7 @@ class MasterClientHandlerTests(NeoUnitTestBase):
# Asking again to pack will cause an immediate error
# Asking again to pack will cause an immediate error
storage_uuid
=
self
.
identifyToMasterNode
(
port
=
10022
)
storage_uuid
=
self
.
identifyToMasterNode
(
port
=
10022
)
storage_conn
=
self
.
getFakeConnection
(
storage_uuid
,
storage_conn
=
self
.
getFakeConnection
(
storage_uuid
,
self
.
storage_address
)
self
.
storage_address
,
is_server
=
True
)
self
.
app
.
nm
.
getByUUID
(
storage_uuid
).
setConnection
(
storage_conn
)
self
.
app
.
nm
.
getByUUID
(
storage_uuid
).
setConnection
(
storage_conn
)
self
.
service
.
askPack
(
conn
,
tid
)
self
.
service
.
askPack
(
conn
,
tid
)
self
.
checkNoPacketSent
(
storage_conn
)
self
.
checkNoPacketSent
(
storage_conn
)
...
...
neo/tests/master/testElectionHandler.py
View file @
4bedd3fc
...
@@ -225,13 +225,13 @@ class MasterServerElectionTests(MasterClientElectionTestBase):
...
@@ -225,13 +225,13 @@ class MasterServerElectionTests(MasterClientElectionTestBase):
def
_tearDown
(
self
,
success
):
def
_tearDown
(
self
,
success
):
NeoUnitTestBase
.
_tearDown
(
self
,
success
)
NeoUnitTestBase
.
_tearDown
(
self
,
success
)
# restore environ
ne
ment
# restore environment
del
ClientConnection
.
_addPacket
del
ClientConnection
.
_addPacket
def
test_requestIdentification1
(
self
):
def
test_requestIdentification1
(
self
):
""" A non-master node request identification """
""" A non-master node request identification """
node
,
conn
=
self
.
identifyToMasterNode
()
node
,
conn
=
self
.
identifyToMasterNode
()
args
=
(
node
.
getUUID
(),
node
.
getAddress
(),
self
.
app
.
name
)
args
=
node
.
getUUID
(),
node
.
getAddress
(),
self
.
app
.
name
,
None
self
.
assertRaises
(
protocol
.
NotReadyError
,
self
.
assertRaises
(
protocol
.
NotReadyError
,
self
.
election
.
requestIdentification
,
self
.
election
.
requestIdentification
,
conn
,
NodeTypes
.
CLIENT
,
*
args
)
conn
,
NodeTypes
.
CLIENT
,
*
args
)
...
@@ -240,7 +240,7 @@ class MasterServerElectionTests(MasterClientElectionTestBase):
...
@@ -240,7 +240,7 @@ class MasterServerElectionTests(MasterClientElectionTestBase):
""" A broken master node request identification """
""" A broken master node request identification """
node
,
conn
=
self
.
identifyToMasterNode
()
node
,
conn
=
self
.
identifyToMasterNode
()
node
.
setBroken
()
node
.
setBroken
()
args
=
(
node
.
getUUID
(),
node
.
getAddress
(),
self
.
app
.
name
)
args
=
node
.
getUUID
(),
node
.
getAddress
(),
self
.
app
.
name
,
None
self
.
assertRaises
(
protocol
.
BrokenNodeDisallowedError
,
self
.
assertRaises
(
protocol
.
BrokenNodeDisallowedError
,
self
.
election
.
requestIdentification
,
self
.
election
.
requestIdentification
,
conn
,
NodeTypes
.
MASTER
,
*
args
)
conn
,
NodeTypes
.
MASTER
,
*
args
)
...
@@ -248,7 +248,7 @@ class MasterServerElectionTests(MasterClientElectionTestBase):
...
@@ -248,7 +248,7 @@ class MasterServerElectionTests(MasterClientElectionTestBase):
def
test_requestIdentification4
(
self
):
def
test_requestIdentification4
(
self
):
""" No conflict """
""" No conflict """
node
,
conn
=
self
.
identifyToMasterNode
()
node
,
conn
=
self
.
identifyToMasterNode
()
args
=
(
node
.
getUUID
(),
node
.
getAddress
(),
self
.
app
.
name
)
args
=
node
.
getUUID
(),
node
.
getAddress
(),
self
.
app
.
name
,
None
self
.
election
.
requestIdentification
(
conn
,
self
.
election
.
requestIdentification
(
conn
,
NodeTypes
.
MASTER
,
*
args
)
NodeTypes
.
MASTER
,
*
args
)
self
.
checkUUIDSet
(
conn
,
node
.
getUUID
())
self
.
checkUUIDSet
(
conn
,
node
.
getUUID
())
...
@@ -280,11 +280,12 @@ class MasterServerElectionTests(MasterClientElectionTestBase):
...
@@ -280,11 +280,12 @@ class MasterServerElectionTests(MasterClientElectionTestBase):
conn
=
self
.
__getClient
()
conn
=
self
.
__getClient
()
self
.
checkNotReadyErrorRaised
(
self
.
checkNotReadyErrorRaised
(
self
.
election
.
requestIdentification
,
self
.
election
.
requestIdentification
,
conn
=
conn
,
conn
,
node_type
=
NodeTypes
.
CLIENT
,
NodeTypes
.
CLIENT
,
uuid
=
conn
.
getUUID
(),
conn
.
getUUID
(),
address
=
conn
.
getAddress
(),
conn
.
getAddress
(),
name
=
self
.
app
.
name
self
.
app
.
name
,
None
,
)
)
def
_requestIdentification
(
self
):
def
_requestIdentification
(
self
):
...
@@ -297,6 +298,7 @@ class MasterServerElectionTests(MasterClientElectionTestBase):
...
@@ -297,6 +298,7 @@ class MasterServerElectionTests(MasterClientElectionTestBase):
peer_uuid
,
peer_uuid
,
address
,
address
,
self
.
app
.
name
,
self
.
app
.
name
,
None
,
)
)
node_type
,
uuid
,
partitions
,
replicas
,
_peer_uuid
,
primary
,
\
node_type
,
uuid
,
partitions
,
replicas
,
_peer_uuid
,
primary
,
\
master_list
=
self
.
checkAcceptIdentification
(
conn
,
decode
=
True
)
master_list
=
self
.
checkAcceptIdentification
(
conn
,
decode
=
True
)
...
...
neo/tests/master/testMasterApp.py
View file @
4bedd3fc
...
@@ -41,8 +41,8 @@ class MasterAppTests(NeoUnitTestBase):
...
@@ -41,8 +41,8 @@ class MasterAppTests(NeoUnitTestBase):
client
=
self
.
app
.
nm
.
createClient
(
uuid
=
client_uuid
)
client
=
self
.
app
.
nm
.
createClient
(
uuid
=
client_uuid
)
# create conn and patch em
# create conn and patch em
master_conn
=
self
.
getFakeConnection
()
master_conn
=
self
.
getFakeConnection
()
storage_conn
=
self
.
getFakeConnection
()
storage_conn
=
self
.
getFakeConnection
(
is_server
=
True
)
client_conn
=
self
.
getFakeConnection
()
client_conn
=
self
.
getFakeConnection
(
is_server
=
True
)
master
.
setConnection
(
master_conn
)
master
.
setConnection
(
master_conn
)
storage
.
setConnection
(
storage_conn
)
storage
.
setConnection
(
storage_conn
)
client
.
setConnection
(
client_conn
)
client
.
setConnection
(
client_conn
)
...
...
neo/tests/master/testMasterPT.py
View file @
4bedd3fc
...
@@ -21,7 +21,6 @@ from .. import NeoUnitTestBase
...
@@ -21,7 +21,6 @@ from .. import NeoUnitTestBase
from
neo.lib.protocol
import
NodeStates
,
CellStates
from
neo.lib.protocol
import
NodeStates
,
CellStates
from
neo.lib.pt
import
PartitionTableException
from
neo.lib.pt
import
PartitionTableException
from
neo.master.pt
import
PartitionTable
from
neo.master.pt
import
PartitionTable
from
neo.lib.node
import
StorageNode
class
MasterPartitionTableTests
(
NeoUnitTestBase
):
class
MasterPartitionTableTests
(
NeoUnitTestBase
):
...
@@ -55,19 +54,19 @@ class MasterPartitionTableTests(NeoUnitTestBase):
...
@@ -55,19 +54,19 @@ class MasterPartitionTableTests(NeoUnitTestBase):
# create nodes
# create nodes
uuid1
=
self
.
getStorageUUID
()
uuid1
=
self
.
getStorageUUID
()
server1
=
(
"127.0.0.1"
,
19001
)
server1
=
(
"127.0.0.1"
,
19001
)
sn1
=
StorageNode
(
Mock
(),
server1
,
uuid1
)
sn1
=
self
.
createStorage
(
server1
,
uuid1
)
uuid2
=
self
.
getStorageUUID
()
uuid2
=
self
.
getStorageUUID
()
server2
=
(
"127.0.0.2"
,
19002
)
server2
=
(
"127.0.0.2"
,
19002
)
sn2
=
StorageNode
(
Mock
(),
server2
,
uuid2
)
sn2
=
self
.
createStorage
(
server2
,
uuid2
)
uuid3
=
self
.
getStorageUUID
()
uuid3
=
self
.
getStorageUUID
()
server3
=
(
"127.0.0.3"
,
19003
)
server3
=
(
"127.0.0.3"
,
19003
)
sn3
=
StorageNode
(
Mock
(),
server3
,
uuid3
)
sn3
=
self
.
createStorage
(
server3
,
uuid3
)
uuid4
=
self
.
getStorageUUID
()
uuid4
=
self
.
getStorageUUID
()
server4
=
(
"127.0.0.4"
,
19004
)
server4
=
(
"127.0.0.4"
,
19004
)
sn4
=
StorageNode
(
Mock
(),
server4
,
uuid4
)
sn4
=
self
.
createStorage
(
server4
,
uuid4
)
uuid5
=
self
.
getStorageUUID
()
uuid5
=
self
.
getStorageUUID
()
server5
=
(
"127.0.0.5"
,
19005
)
server5
=
(
"127.0.0.5"
,
19005
)
sn5
=
StorageNode
(
Mock
(),
server5
,
uuid5
)
sn5
=
self
.
createStorage
(
server5
,
uuid5
)
# create partition table
# create partition table
num_partitions
=
5
num_partitions
=
5
num_replicas
=
3
num_replicas
=
3
...
@@ -117,7 +116,7 @@ class MasterPartitionTableTests(NeoUnitTestBase):
...
@@ -117,7 +116,7 @@ class MasterPartitionTableTests(NeoUnitTestBase):
self
.
assertEqual
(
cell
.
getState
(),
CellStates
.
UP_TO_DATE
)
self
.
assertEqual
(
cell
.
getState
(),
CellStates
.
UP_TO_DATE
)
def
test_15_dropNodeList
(
self
):
def
test_15_dropNodeList
(
self
):
sn
=
[
StorageNode
(
Mock
(),
None
,
i
+
1
,
NodeStates
.
RUNNING
)
sn
=
[
self
.
createStorage
(
None
,
i
+
1
,
NodeStates
.
RUNNING
)
for
i
in
xrange
(
3
)]
for
i
in
xrange
(
3
)]
pt
=
PartitionTable
(
3
,
0
)
pt
=
PartitionTable
(
3
,
0
)
pt
.
setCell
(
0
,
sn
[
0
],
CellStates
.
OUT_OF_DATE
)
pt
.
setCell
(
0
,
sn
[
0
],
CellStates
.
OUT_OF_DATE
)
...
@@ -153,22 +152,22 @@ class MasterPartitionTableTests(NeoUnitTestBase):
...
@@ -153,22 +152,22 @@ class MasterPartitionTableTests(NeoUnitTestBase):
# add nodes
# add nodes
uuid1
=
self
.
getStorageUUID
()
uuid1
=
self
.
getStorageUUID
()
server1
=
(
"127.0.0.1"
,
19001
)
server1
=
(
"127.0.0.1"
,
19001
)
sn1
=
StorageNode
(
Mock
(),
server1
,
uuid1
,
NodeStates
.
RUNNING
)
sn1
=
self
.
createStorage
(
server1
,
uuid1
,
NodeStates
.
RUNNING
)
# add not running node
# add not running node
uuid2
=
self
.
getStorageUUID
()
uuid2
=
self
.
getStorageUUID
()
server2
=
(
"127.0.0.2"
,
19001
)
server2
=
(
"127.0.0.2"
,
19001
)
sn2
=
StorageNode
(
Mock
(),
server2
,
uuid2
)
sn2
=
self
.
createStorage
(
server2
,
uuid2
)
sn2
.
setState
(
NodeStates
.
TEMPORARILY_DOWN
)
sn2
.
setState
(
NodeStates
.
TEMPORARILY_DOWN
)
# add node without uuid
# add node without uuid
server3
=
(
"127.0.0.3"
,
19001
)
server3
=
(
"127.0.0.3"
,
19001
)
sn3
=
StorageNode
(
Mock
(),
server3
,
None
,
NodeStates
.
RUNNING
)
sn3
=
self
.
createStorage
(
server3
,
None
,
NodeStates
.
RUNNING
)
# add clear node
# add clear node
uuid4
=
self
.
getStorageUUID
()
uuid4
=
self
.
getStorageUUID
()
server4
=
(
"127.0.0.4"
,
19001
)
server4
=
(
"127.0.0.4"
,
19001
)
sn4
=
StorageNode
(
Mock
(),
server4
,
uuid4
,
NodeStates
.
RUNNING
)
sn4
=
self
.
createStorage
(
server4
,
uuid4
,
NodeStates
.
RUNNING
)
uuid5
=
self
.
getStorageUUID
()
uuid5
=
self
.
getStorageUUID
()
server5
=
(
"127.0.0.5"
,
1900
)
server5
=
(
"127.0.0.5"
,
1900
)
sn5
=
StorageNode
(
Mock
(),
server5
,
uuid5
,
NodeStates
.
RUNNING
)
sn5
=
self
.
createStorage
(
server5
,
uuid5
,
NodeStates
.
RUNNING
)
# make the table
# make the table
pt
.
make
([
sn1
,
sn2
,
sn3
,
sn4
,
sn5
])
pt
.
make
([
sn1
,
sn2
,
sn3
,
sn4
,
sn5
])
# check it's ok, only running nodes and node with uuid
# check it's ok, only running nodes and node with uuid
...
@@ -231,7 +230,7 @@ class MasterPartitionTableTests(NeoUnitTestBase):
...
@@ -231,7 +230,7 @@ class MasterPartitionTableTests(NeoUnitTestBase):
return
change_list
return
change_list
def
test_17_tweak
(
self
):
def
test_17_tweak
(
self
):
sn
=
[
StorageNode
(
Mock
(),
None
,
i
+
1
,
NodeStates
.
RUNNING
)
sn
=
[
self
.
createStorage
(
None
,
i
+
1
,
NodeStates
.
RUNNING
)
for
i
in
xrange
(
5
)]
for
i
in
xrange
(
5
)]
pt
=
PartitionTable
(
5
,
2
)
pt
=
PartitionTable
(
5
,
2
)
# part 0
# part 0
...
...
neo/tests/master/testStorageHandler.py
View file @
4bedd3fc
...
@@ -63,7 +63,7 @@ class MasterStorageHandlerTests(NeoUnitTestBase):
...
@@ -63,7 +63,7 @@ class MasterStorageHandlerTests(NeoUnitTestBase):
uuid
=
self
.
getNewUUID
(
node_type
)
uuid
=
self
.
getNewUUID
(
node_type
)
node
=
nm
.
createFromNodeType
(
node_type
,
address
=
(
ip
,
port
),
node
=
nm
.
createFromNodeType
(
node_type
,
address
=
(
ip
,
port
),
uuid
=
uuid
)
uuid
=
uuid
)
conn
=
self
.
getFakeConnection
(
node
.
getUUID
(),
node
.
getAddress
())
conn
=
self
.
getFakeConnection
(
node
.
getUUID
(),
node
.
getAddress
()
,
True
)
node
.
setConnection
(
conn
)
node
.
setConnection
(
conn
)
return
(
node
,
conn
)
return
(
node
,
conn
)
...
@@ -160,7 +160,7 @@ class MasterStorageHandlerTests(NeoUnitTestBase):
...
@@ -160,7 +160,7 @@ class MasterStorageHandlerTests(NeoUnitTestBase):
self
.
assertEqual
(
lptid
,
self
.
app
.
pt
.
getID
())
self
.
assertEqual
(
lptid
,
self
.
app
.
pt
.
getID
())
def
test_answerPack
(
self
):
def
test_answerPack
(
self
):
# Note: incom
m
ing status has no meaning here, so it's left to False.
# Note: incoming status has no meaning here, so it's left to False.
node1
,
conn1
=
self
.
_getStorage
()
node1
,
conn1
=
self
.
_getStorage
()
node2
,
conn2
=
self
.
_getStorage
()
node2
,
conn2
=
self
.
_getStorage
()
self
.
app
.
packing
=
None
self
.
app
.
packing
=
None
...
...
neo/tests/master/testTransactions.py
View file @
4bedd3fc
...
@@ -169,7 +169,7 @@ class testTransactionManager(NeoUnitTestBase):
...
@@ -169,7 +169,7 @@ class testTransactionManager(NeoUnitTestBase):
"""
"""
Transaction lock is present to ensure invalidation TIDs are sent in
Transaction lock is present to ensure invalidation TIDs are sent in
strictly increasing order.
strictly increasing order.
Note: this implementation might change later,
to allow more para
lelism.
Note: this implementation might change later,
for more paral
lelism.
"""
"""
client_uuid
,
client
=
self
.
makeNode
(
NodeTypes
.
CLIENT
)
client_uuid
,
client
=
self
.
makeNode
(
NodeTypes
.
CLIENT
)
tm
=
TransactionManager
(
lambda
tid
,
txn
:
None
)
tm
=
TransactionManager
(
lambda
tid
,
txn
:
None
)
...
...
neo/tests/storage/testIdentificationHandler.py
View file @
4bedd3fc
...
@@ -17,7 +17,7 @@
...
@@ -17,7 +17,7 @@
import
unittest
import
unittest
from
mock
import
Mock
from
mock
import
Mock
from
..
import
NeoUnitTestBase
from
..
import
NeoUnitTestBase
from
neo.lib.protocol
import
NodeTypes
,
NotReadyError
,
\
from
neo.lib.protocol
import
Node
States
,
Node
Types
,
NotReadyError
,
\
BrokenNodeDisallowedError
BrokenNodeDisallowedError
from
neo.lib.pt
import
PartitionTable
from
neo.lib.pt
import
PartitionTable
from
neo.storage.app
import
Application
from
neo.storage.app
import
Application
...
@@ -50,6 +50,7 @@ class StorageIdentificationHandlerTests(NeoUnitTestBase):
...
@@ -50,6 +50,7 @@ class StorageIdentificationHandlerTests(NeoUnitTestBase):
self
.
getClientUUID
(),
self
.
getClientUUID
(),
None
,
None
,
self
.
app
.
name
,
self
.
app
.
name
,
None
,
)
)
self
.
app
.
ready
=
True
self
.
app
.
ready
=
True
self
.
assertRaises
(
self
.
assertRaises
(
...
@@ -60,6 +61,7 @@ class StorageIdentificationHandlerTests(NeoUnitTestBase):
...
@@ -60,6 +61,7 @@ class StorageIdentificationHandlerTests(NeoUnitTestBase):
self
.
getStorageUUID
(),
self
.
getStorageUUID
(),
None
,
None
,
self
.
app
.
name
,
self
.
app
.
name
,
None
,
)
)
def
test_requestIdentification3
(
self
):
def
test_requestIdentification3
(
self
):
...
@@ -75,19 +77,20 @@ class StorageIdentificationHandlerTests(NeoUnitTestBase):
...
@@ -75,19 +77,20 @@ class StorageIdentificationHandlerTests(NeoUnitTestBase):
uuid
,
uuid
,
None
,
None
,
self
.
app
.
name
,
self
.
app
.
name
,
None
,
)
)
def
test_requestIdentification2
(
self
):
def
test_requestIdentification2
(
self
):
""" accepted client must be connected and running """
""" accepted client must be connected and running """
uuid
=
self
.
getClientUUID
()
uuid
=
self
.
getClientUUID
()
conn
=
self
.
getFakeConnection
(
uuid
=
uuid
)
conn
=
self
.
getFakeConnection
(
uuid
=
uuid
)
node
=
self
.
app
.
nm
.
createClient
(
uuid
=
uuid
)
node
=
self
.
app
.
nm
.
createClient
(
uuid
=
uuid
,
state
=
NodeStates
.
RUNNING
)
master
=
(
self
.
local_ip
,
3000
)
master
=
(
self
.
local_ip
,
3000
)
self
.
app
.
master_node
=
Mock
({
self
.
app
.
master_node
=
Mock
({
'getAddress'
:
master
,
'getAddress'
:
master
,
})
})
self
.
identification
.
requestIdentification
(
conn
,
NodeTypes
.
CLIENT
,
uuid
,
self
.
identification
.
requestIdentification
(
conn
,
NodeTypes
.
CLIENT
,
uuid
,
None
,
self
.
app
.
name
)
None
,
self
.
app
.
name
,
None
)
self
.
assertTrue
(
node
.
isRunning
())
self
.
assertTrue
(
node
.
isRunning
())
self
.
assertTrue
(
node
.
isConnected
())
self
.
assertTrue
(
node
.
isConnected
())
self
.
assertEqual
(
node
.
getUUID
(),
uuid
)
self
.
assertEqual
(
node
.
getUUID
(),
uuid
)
...
...
neo/tests/storage/testStorageDBTests.py
View file @
4bedd3fc
...
@@ -167,17 +167,17 @@ class StorageDBTests(NeoUnitTestBase):
...
@@ -167,17 +167,17 @@ class StorageDBTests(NeoUnitTestBase):
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
),
None
)
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-commit
t
ed version
with
self
.
commitTransaction
(
tid1
,
objs1
,
txn1
):
with
self
.
commitTransaction
(
tid1
,
objs1
,
txn1
):
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
),
None
)
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 commited version
# one commit
t
ed version
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
),
OBJECT_T1_NO_NEXT
)
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
),
OBJECT_T1_NO_NEXT
)
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
,
tid1
),
OBJECT_T1_NO_NEXT
)
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
,
tid1
),
OBJECT_T1_NO_NEXT
)
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
,
before_tid
=
tid1
),
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
,
before_tid
=
tid1
),
FOUND_BUT_NOT_VISIBLE
)
FOUND_BUT_NOT_VISIBLE
)
# two version available, one non-commited
# two version available, one non-commit
t
ed
with
self
.
commitTransaction
(
tid2
,
objs2
,
txn2
):
with
self
.
commitTransaction
(
tid2
,
objs2
,
txn2
):
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
),
OBJECT_T1_NO_NEXT
)
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
),
OBJECT_T1_NO_NEXT
)
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
,
tid1
),
OBJECT_T1_NO_NEXT
)
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
,
tid1
),
OBJECT_T1_NO_NEXT
)
...
@@ -187,7 +187,7 @@ class StorageDBTests(NeoUnitTestBase):
...
@@ -187,7 +187,7 @@ class StorageDBTests(NeoUnitTestBase):
FOUND_BUT_NOT_VISIBLE
)
FOUND_BUT_NOT_VISIBLE
)
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
,
before_tid
=
tid2
),
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
,
before_tid
=
tid2
),
OBJECT_T1_NO_NEXT
)
OBJECT_T1_NO_NEXT
)
# two commited versions
# two commit
t
ed versions
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
),
OBJECT_T2
)
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
),
OBJECT_T2
)
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
,
tid1
),
OBJECT_T1_NEXT
)
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
,
tid1
),
OBJECT_T1_NEXT
)
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
,
before_tid
=
tid1
),
self
.
assertEqual
(
self
.
db
.
getObject
(
oid1
,
before_tid
=
tid1
),
...
...
neo/tests/storage/testTransactions.py
View file @
4bedd3fc
...
@@ -187,7 +187,7 @@ class TransactionManagerTests(NeoUnitTestBase):
...
@@ -187,7 +187,7 @@ class TransactionManagerTests(NeoUnitTestBase):
ttid1
,
serial
,
*
obj
)
ttid1
,
serial
,
*
obj
)
def
testResolvableConflict
(
self
):
def
testResolvableConflict
(
self
):
""" Try to store an object with the la
s
test revision """
""" Try to store an object with the latest revision """
uuid
=
self
.
getClientUUID
()
uuid
=
self
.
getClientUUID
()
tid
,
txn
=
self
.
_getTransaction
()
tid
,
txn
=
self
.
_getTransaction
()
serial
,
obj
=
self
.
_getObject
(
1
)
serial
,
obj
=
self
.
_getObject
(
1
)
...
...
neo/tests/testBootstrap.py
View file @
4bedd3fc
...
@@ -28,7 +28,7 @@ class BootstrapManagerTests(NeoUnitTestBase):
...
@@ -28,7 +28,7 @@ class BootstrapManagerTests(NeoUnitTestBase):
# create an application object
# create an application object
config
=
self
.
getStorageConfiguration
()
config
=
self
.
getStorageConfiguration
()
self
.
app
=
Application
(
config
)
self
.
app
=
Application
(
config
)
self
.
bootstrap
=
BootstrapManager
(
self
.
app
,
'main'
,
NodeTypes
.
STORAGE
)
self
.
bootstrap
=
BootstrapManager
(
self
.
app
,
NodeTypes
.
STORAGE
)
# define some variable to simulate client and storage node
# define some variable to simulate client and storage node
self
.
master_port
=
10010
self
.
master_port
=
10010
self
.
storage_port
=
10020
self
.
storage_port
=
10020
...
...
neo/tests/testConnection.py
View file @
4bedd3fc
...
@@ -330,7 +330,7 @@ class HandlerSwitcherTests(NeoUnitTestBase):
...
@@ -330,7 +330,7 @@ class HandlerSwitcherTests(NeoUnitTestBase):
r2
=
self
.
_makeRequest
(
2
)
r2
=
self
.
_makeRequest
(
2
)
a2
=
self
.
_makeAnswer
(
2
)
a2
=
self
.
_makeAnswer
(
2
)
h
=
self
.
_makeHandler
()
h
=
self
.
_makeHandler
()
# emit requests aroun
g
state setHandler
# emit requests aroun
d
state setHandler
self
.
_handlers
.
emit
(
r1
,
0
,
None
)
self
.
_handlers
.
emit
(
r1
,
0
,
None
)
applied
=
self
.
_handlers
.
setHandler
(
h
)
applied
=
self
.
_handlers
.
setHandler
(
h
)
self
.
assertFalse
(
applied
)
self
.
assertFalse
(
applied
)
...
...
neo/tests/testNodes.py
View file @
4bedd3fc
This diff is collapsed.
Click to expand it.
neo/tests/testPT.py
View file @
4bedd3fc
This diff is collapsed.
Click to expand it.
neo/tests/testUtil.py
View file @
4bedd3fc
...
@@ -22,7 +22,7 @@ from neo.lib.util import ReadBuffer, parseNodeAddress
...
@@ -22,7 +22,7 @@ from neo.lib.util import ReadBuffer, parseNodeAddress
class
UtilTests
(
NeoUnitTestBase
):
class
UtilTests
(
NeoUnitTestBase
):
def
test_parseNodeAddress
(
self
):
def
test_parseNodeAddress
(
self
):
""" Parsing of addesses """
""" Parsing of add
r
esses """
def
test
(
parsed
,
*
args
):
def
test
(
parsed
,
*
args
):
self
.
assertEqual
(
parsed
,
parseNodeAddress
(
*
args
))
self
.
assertEqual
(
parsed
,
parseNodeAddress
(
*
args
))
http_port
=
socket
.
getservbyname
(
'http'
)
http_port
=
socket
.
getservbyname
(
'http'
)
...
...
neo/tests/threaded/test.py
View file @
4bedd3fc
...
@@ -27,14 +27,14 @@ from ZODB import DB, POSException
...
@@ -27,14 +27,14 @@ from ZODB import DB, POSException
from
ZODB.DB
import
TransactionalUndo
from
ZODB.DB
import
TransactionalUndo
from
neo.storage.transactions
import
TransactionManager
,
\
from
neo.storage.transactions
import
TransactionManager
,
\
DelayedError
,
ConflictError
DelayedError
,
ConflictError
from
neo.lib.connection
import
MTClientConnection
from
neo.lib.connection
import
ServerConnection
,
MTClientConnection
from
neo.lib.exception
import
DatabaseFailure
,
StoppedOperation
from
neo.lib.exception
import
DatabaseFailure
,
StoppedOperation
from
neo.lib.protocol
import
CellStates
,
ClusterStates
,
NodeStates
,
Packets
,
\
from
neo.lib.protocol
import
CellStates
,
ClusterStates
,
NodeStates
,
Packets
,
\
ZERO_TID
ZERO_
OID
,
ZERO_
TID
from
..
import
expectedFailure
,
Patch
from
..
import
expectedFailure
,
Patch
from
.
import
LockLock
,
NEOCluster
,
NEOThreadedTest
from
.
import
LockLock
,
NEOCluster
,
NEOThreadedTest
from
neo.lib.util
import
add64
,
makeChecksum
,
p64
,
u64
from
neo.lib.util
import
add64
,
makeChecksum
,
p64
,
u64
from
neo.client.exception
import
NEOStorageError
from
neo.client.exception
import
NEO
PrimaryMasterLost
,
NEO
StorageError
from
neo.client.pool
import
CELL_CONNECTED
,
CELL_GOOD
from
neo.client.pool
import
CELL_CONNECTED
,
CELL_GOOD
from
neo.master.handlers.client
import
ClientServiceHandler
from
neo.master.handlers.client
import
ClientServiceHandler
from
neo.storage.handlers.client
import
ClientOperationHandler
from
neo.storage.handlers.client
import
ClientOperationHandler
...
@@ -970,7 +970,7 @@ class Test(NEOThreadedTest):
...
@@ -970,7 +970,7 @@ class Test(NEOThreadedTest):
self
.
assertFalse
(
storage
.
tm
.
_transaction_dict
)
self
.
assertFalse
(
storage
.
tm
.
_transaction_dict
)
finally
:
finally
:
db
.
close
()
db
.
close
()
# Check we did't get an invalidation, which would cause an
# Check we did
n
't get an invalidation, which would cause an
# assertion failure in the cache. Connection does the same check in
# assertion failure in the cache. Connection does the same check in
# _setstate_noncurrent so this could be also done by starting a
# _setstate_noncurrent so this could be also done by starting a
# transaction before the last one, and clearing the cache before
# transaction before the last one, and clearing the cache before
...
@@ -1061,17 +1061,40 @@ class Test(NEOThreadedTest):
...
@@ -1061,17 +1061,40 @@ class Test(NEOThreadedTest):
cluster
.
stop
()
cluster
.
stop
()
def
testClientFailureDuringTpcFinish
(
self
):
def
testClientFailureDuringTpcFinish
(
self
):
def
delayAskLockInformation
(
conn
,
packet
):
"""
if
isinstance
(
packet
,
Packets
.
AskLockInformation
):
Third scenario:
C M S | TID known by
---- Finish -----> |
---- Disconnect -- ----- Lock ------> |
----- C down ----> |
---- Connect ----> | M
----- C up ------> |
<---- Locked ----- |
------------------------------------------------+--------------
-- unlock ... |
---- FinalTID ---> | S (TM)
---- Connect + FinalTID --------------> |
... unlock ---> |
------------------------------------------------+--------------
| S (DM)
"""
def
delayAnswerLockInformation
(
conn
,
packet
):
if
isinstance
(
packet
,
Packets
.
AnswerInformationLocked
):
cluster
.
client
.
master_conn
.
close
()
cluster
.
client
.
master_conn
.
close
()
return
True
return
True
def
askFinalTID
(
orig
,
*
args
):
def
askFinalTID
(
orig
,
*
args
):
m2s
.
remove
(
delayAsk
LockInformation
)
s2m
.
remove
(
delayAnswer
LockInformation
)
orig
(
*
args
)
orig
(
*
args
)
def
_getFinalTID
(
orig
,
ttid
):
def
_getFinalTID
(
orig
,
ttid
):
m2s
.
remove
(
delayAsk
LockInformation
)
s2m
.
remove
(
delayAnswer
LockInformation
)
self
.
tic
()
self
.
tic
()
return
orig
(
ttid
)
return
orig
(
ttid
)
def
_connectToPrimaryNode
(
orig
):
conn
=
orig
()
self
.
tic
()
s2m
.
remove
(
delayAnswerLockInformation
)
return
conn
cluster
=
NEOCluster
()
cluster
=
NEOCluster
()
try
:
try
:
cluster
.
start
()
cluster
.
start
()
...
@@ -1079,25 +1102,30 @@ class Test(NEOThreadedTest):
...
@@ -1079,25 +1102,30 @@ class Test(NEOThreadedTest):
r
=
c
.
root
()
r
=
c
.
root
()
r
[
'x'
]
=
PCounter
()
r
[
'x'
]
=
PCounter
()
tid0
=
r
.
_p_serial
tid0
=
r
.
_p_serial
with
cluster
.
master
.
filterConnection
(
cluster
.
storage
)
as
m2s
:
with
cluster
.
storage
.
filterConnection
(
cluster
.
master
)
as
s2m
:
m2s
.
add
(
delayAsk
LockInformation
,
s2m
.
add
(
delayAnswer
LockInformation
,
Patch
(
ClientServiceHandler
,
askFinalTID
=
askFinalTID
))
Patch
(
ClientServiceHandler
,
askFinalTID
=
askFinalTID
))
t
.
commit
()
# the final TID is returned by the master
t
.
commit
()
# the final TID is returned by the master
t
.
begin
()
t
.
begin
()
r
[
'x'
].
value
+=
1
r
[
'x'
].
value
+=
1
tid1
=
r
.
_p_serial
tid1
=
r
.
_p_serial
self
.
assertTrue
(
tid0
<
tid1
)
self
.
assertTrue
(
tid0
<
tid1
)
with
cluster
.
master
.
filterConnection
(
cluster
.
storage
)
as
m2s
:
with
cluster
.
storage
.
filterConnection
(
cluster
.
master
)
as
s2m
:
m2s
.
add
(
delayAsk
LockInformation
,
s2m
.
add
(
delayAnswer
LockInformation
,
Patch
(
cluster
.
client
,
_getFinalTID
=
_getFinalTID
))
Patch
(
cluster
.
client
,
_getFinalTID
=
_getFinalTID
))
t
.
commit
()
# the final TID is returned by the storage backend
t
.
commit
()
# the final TID is returned by the storage backend
t
.
begin
()
t
.
begin
()
r
[
'x'
].
value
+=
1
r
[
'x'
].
value
+=
1
tid2
=
r
[
'x'
].
_p_serial
tid2
=
r
[
'x'
].
_p_serial
self
.
assertTrue
(
tid1
<
tid2
)
self
.
assertTrue
(
tid1
<
tid2
)
with
cluster
.
master
.
filterConnection
(
cluster
.
storage
)
as
m2s
:
# The whole test would be simpler if we always delayed the
m2s
.
add
(
delayAskLockInformation
,
# AskLockInformation packet. However, it would also delay
Patch
(
cluster
.
client
,
_getFinalTID
=
_getFinalTID
))
# NotifyNodeInformation and the client would fail to connect
# to the storage node.
with
cluster
.
storage
.
filterConnection
(
cluster
.
master
)
as
s2m
,
\
cluster
.
master
.
filterConnection
(
cluster
.
storage
)
as
m2s
:
s2m
.
add
(
delayAnswerLockInformation
,
Patch
(
cluster
.
client
,
_connectToPrimaryNode
=
_connectToPrimaryNode
))
m2s
.
add
(
lambda
conn
,
packet
:
m2s
.
add
(
lambda
conn
,
packet
:
isinstance
(
packet
,
Packets
.
NotifyUnlockInformation
))
isinstance
(
packet
,
Packets
.
NotifyUnlockInformation
))
t
.
commit
()
# the final TID is returned by the storage (tm)
t
.
commit
()
# the final TID is returned by the storage (tm)
...
@@ -1292,6 +1320,8 @@ class Test(NEOThreadedTest):
...
@@ -1292,6 +1320,8 @@ class Test(NEOThreadedTest):
m2c
,
=
cluster
.
master
.
getConnectionList
(
cluster
.
client
)
m2c
,
=
cluster
.
master
.
getConnectionList
(
cluster
.
client
)
cluster
.
client
.
_cache
.
clear
()
cluster
.
client
.
_cache
.
clear
()
c
.
cacheMinimize
()
c
.
cacheMinimize
()
# Make the master disconnects the client when the latter is about
# to send a AskObject packet to the storage node.
with
cluster
.
client
.
filterConnection
(
cluster
.
storage
)
as
c2s
:
with
cluster
.
client
.
filterConnection
(
cluster
.
storage
)
as
c2s
:
c2s
.
add
(
disconnect
)
c2s
.
add
(
disconnect
)
# Storages are currently notified of clients that get
# Storages are currently notified of clients that get
...
@@ -1299,9 +1329,75 @@ class Test(NEOThreadedTest):
...
@@ -1299,9 +1329,75 @@ class Test(NEOThreadedTest):
# Should it change, the clients would have to disconnect on
# Should it change, the clients would have to disconnect on
# their own.
# their own.
self
.
assertRaises
(
TransientError
,
getattr
,
c
,
"root"
)
self
.
assertRaises
(
TransientError
,
getattr
,
c
,
"root"
)
uuid
=
cluster
.
client
.
uuid
# Let's use a second client to steal the node id of the first one.
client
=
cluster
.
newClient
()
try
:
client
.
sync
()
self
.
assertEqual
(
uuid
,
client
.
uuid
)
# The client reconnects successfully to the master and storage,
# with a different node id. This time, we get a different error
# if it's only disconnected from the storage.
with
Patch
(
ClientOperationHandler
,
with
Patch
(
ClientOperationHandler
,
askObject
=
lambda
orig
,
self
,
conn
,
*
args
:
conn
.
close
()):
askObject
=
lambda
orig
,
self
,
conn
,
*
args
:
conn
.
close
()):
self
.
assertRaises
(
NEOStorageError
,
getattr
,
c
,
"root"
)
self
.
assertRaises
(
NEOStorageError
,
getattr
,
c
,
"root"
)
self
.
assertNotEqual
(
uuid
,
cluster
.
client
.
uuid
)
# Second reconnection, for a successful load.
c
.
root
finally
:
client
.
close
()
finally
:
cluster
.
stop
()
def
testIdTimestamp
(
self
):
"""
Given a master M, a storage S, and 2 clients Ca and Cb.
While Ca(id=1) is being identified by S:
1. connection between Ca and M breaks
2. M -> S: C1 down
3. Cb connect to M: id=1
4. M -> S: C1 up
5. S processes RequestIdentification from Ca with id=1
At 5, S must reject Ca, otherwise Cb can't connect to S. This is where
id timestamps come into play: with C1 up since t2, S rejects Ca due to
a request with t1 < t2.
To avoid issues with clocks that are out of sync, the client gets its
connection timestamp by being notified about itself from the master.
"""
s2c
=
[]
def
__init__
(
orig
,
self
,
*
args
,
**
kw
):
orig
(
self
,
*
args
,
**
kw
)
self
.
readable
=
bool
s2c
.
append
(
self
)
ll
()
def
connectToStorage
(
client
):
next
(
client
.
cp
.
iterateForObject
(
0
))
cluster
=
NEOCluster
()
try
:
cluster
.
start
()
Ca
=
cluster
.
client
Ca
.
pt
# only connect to the master
# In a separate thread, connect to the storage but suspend the
# processing of the RequestIdentification packet, until the
# storage is notified about the existence of the other client.
with
LockLock
()
as
ll
,
Patch
(
ServerConnection
,
__init__
=
__init__
):
t
=
self
.
newThread
(
connectToStorage
,
Ca
)
ll
()
s2c
,
=
s2c
m2c
,
=
cluster
.
master
.
getConnectionList
(
cluster
.
client
)
m2c
.
close
()
Cb
=
cluster
.
newClient
()
try
:
Cb
.
pt
# only connect to the master
del
s2c
.
readable
self
.
assertRaises
(
NEOPrimaryMasterLost
,
t
.
join
)
self
.
assertTrue
(
s2c
.
isClosed
())
connectToStorage
(
Cb
)
finally
:
Cb
.
close
()
finally
:
finally
:
cluster
.
stop
()
cluster
.
stop
()
...
...
neo/tests/threaded/testReplication.py
View file @
4bedd3fc
...
@@ -302,7 +302,7 @@ class ReplicationTests(NEOThreadedTest):
...
@@ -302,7 +302,7 @@ class ReplicationTests(NEOThreadedTest):
More generally, this checks that when a handler raises when a connection
More generally, this checks that when a handler raises when a connection
is closed voluntarily, the connection is in a consistent state and can
is closed voluntarily, the connection is in a consistent state and can
be, for example, closed again after the exception is ca
tched
, without
be, for example, closed again after the exception is ca
ught
, without
assertion failure.
assertion failure.
"""
"""
conn
,
=
backup
.
master
.
getConnectionList
(
backup
.
upstream
.
master
)
conn
,
=
backup
.
master
.
getConnectionList
(
backup
.
upstream
.
master
)
...
...
tools/coverage-html
View file @
4bedd3fc
...
@@ -3,7 +3,7 @@ for COV in coverage python-coverage
...
@@ -3,7 +3,7 @@ for COV in coverage python-coverage
do
type
$COV
&&
break
do
type
$COV
&&
break
done
>
/dev/null 2>&1
||
exit
done
>
/dev/null 2>&1
||
exit
$COV
html
$COV
html
"
$@
"
# https://bitbucket.org/ned/coveragepy/issues/474/javascript-in-html-captures-all-keys
# https://bitbucket.org/ned/coveragepy/issues/474/javascript-in-html-captures-all-keys
sed
-i
"
sed
-i
"
/assign_shortkeys *=/s/
$/
return;/
/assign_shortkeys *=/s/
$/
return;/
...
...
tools/replication
View file @
4bedd3fc
...
@@ -94,18 +94,18 @@ class ReplicationBenchmark(BenchmarkRunner):
...
@@ -94,18 +94,18 @@ class ReplicationBenchmark(BenchmarkRunner):
return
self
.
buildReport
(
p_time
,
r_time
),
content
return
self
.
buildReport
(
p_time
,
r_time
),
content
def
replicate
(
self
,
neo
):
def
replicate
(
self
,
neo
):
def
number_of_oudated_cell
():
def
number_of_ou
t
dated_cell
():
row_list
=
neo
.
neoctl
.
getPartitionRowList
()[
1
]
row_list
=
neo
.
neoctl
.
getPartitionRowList
()[
1
]
number_of_oudated
=
0
number_of_ou
t
dated
=
0
for
row
in
row_list
:
for
row
in
row_list
:
for
cell
in
row
[
1
]:
for
cell
in
row
[
1
]:
if
cell
[
1
]
==
CellStates
.
OUT_OF_DATE
:
if
cell
[
1
]
==
CellStates
.
OUT_OF_DATE
:
number_of_oudated
+=
1
number_of_ou
t
dated
+=
1
return
number_of_oudated
return
number_of_ou
t
dated
end_time
=
time
.
time
()
+
3600
end_time
=
time
.
time
()
+
3600
while
time
.
time
()
<=
end_time
and
number_of_oudated_cell
()
>
0
:
while
time
.
time
()
<=
end_time
and
number_of_ou
t
dated_cell
()
>
0
:
time
.
sleep
(
1
)
time
.
sleep
(
1
)
if
number_of_oudated_cell
()
>
0
:
if
number_of_ou
t
dated_cell
()
>
0
:
raise
Exception
(
'Replication takes too long'
)
raise
Exception
(
'Replication takes too long'
)
def
buildReport
(
self
,
p_time
,
r_time
):
def
buildReport
(
self
,
p_time
,
r_time
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment