Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neoppod
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
neoppod
Commits
8eb14b01
Commit
8eb14b01
authored
Nov 26, 2016
by
Julien Muchembled
Browse files
Options
Browse Files
Download
Plain Diff
Bump protocol version
parents
54e819ff
9385706f
Pipeline
#3828
skipped
Changes
36
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
36 changed files
with
285 additions
and
313 deletions
+285
-313
app.py
neo/admin/app.py
+3
-8
handler.py
neo/admin/handler.py
+0
-7
app.py
neo/client/app.py
+3
-4
master.py
neo/client/handlers/master.py
+21
-25
storage.py
neo/client/handlers/storage.py
+7
-8
pool.py
neo/client/pool.py
+1
-1
bootstrap.py
neo/lib/bootstrap.py
+7
-10
handler.py
neo/lib/handler.py
+10
-0
node.py
neo/lib/node.py
+31
-18
protocol.py
neo/lib/protocol.py
+16
-9
threaded_app.py
neo/lib/threaded_app.py
+2
-2
app.py
neo/master/app.py
+14
-15
backup_app.py
neo/master/backup_app.py
+3
-3
__init__.py
neo/master/handlers/__init__.py
+7
-10
backup.py
neo/master/handlers/backup.py
+0
-6
client.py
neo/master/handlers/client.py
+2
-4
election.py
neo/master/handlers/election.py
+11
-2
identification.py
neo/master/handlers/identification.py
+30
-13
secondary.py
neo/master/handlers/secondary.py
+10
-20
storage.py
neo/master/handlers/storage.py
+2
-4
neolog.py
neo/scripts/neolog.py
+7
-8
app.py
neo/storage/app.py
+4
-7
checker.py
neo/storage/checker.py
+2
-2
__init__.py
neo/storage/handlers/__init__.py
+2
-2
identification.py
neo/storage/handlers/identification.py
+4
-8
initialization.py
neo/storage/handlers/initialization.py
+0
-3
replicator.py
neo/storage/replicator.py
+2
-1
testClientApp.py
neo/tests/client/testClientApp.py
+2
-7
testMasterHandler.py
neo/tests/client/testMasterHandler.py
+0
-63
__init__.py
neo/tests/functional/__init__.py
+7
-13
testClientHandler.py
neo/tests/master/testClientHandler.py
+0
-12
testElectionHandler.py
neo/tests/master/testElectionHandler.py
+10
-8
testIdentificationHandler.py
neo/tests/storage/testIdentificationHandler.py
+4
-1
testBootstrap.py
neo/tests/testBootstrap.py
+1
-1
testNodes.py
neo/tests/testNodes.py
+5
-5
test.py
neo/tests/threaded/test.py
+55
-3
No files found.
neo/admin/app.py
View file @
8eb14b01
...
...
@@ -105,13 +105,9 @@ class Application(BaseApplication):
"""
self
.
cluster_state
=
None
# search, find, connect and identify to the primary master
bootstrap
=
BootstrapManager
(
self
,
self
.
name
,
NodeTypes
.
ADMIN
,
self
.
uuid
,
self
.
server
)
data
=
bootstrap
.
getPrimaryConnection
()
(
node
,
conn
,
uuid
,
num_partitions
,
num_replicas
)
=
data
self
.
master_node
=
node
self
.
master_conn
=
conn
self
.
uuid
=
uuid
bootstrap
=
BootstrapManager
(
self
,
NodeTypes
.
ADMIN
,
self
.
server
)
self
.
master_node
,
self
.
master_conn
,
num_partitions
,
num_replicas
=
\
bootstrap
.
getPrimaryConnection
()
if
self
.
pt
is
None
:
self
.
pt
=
PartitionTable
(
num_partitions
,
num_replicas
)
...
...
@@ -125,7 +121,6 @@ class Application(BaseApplication):
# passive handler
self
.
master_conn
.
setHandler
(
self
.
master_event_handler
)
self
.
master_conn
.
ask
(
Packets
.
AskClusterState
())
self
.
master_conn
.
ask
(
Packets
.
AskNodeInformation
())
self
.
master_conn
.
ask
(
Packets
.
AskPartitionTable
())
def
sendPartitionTable
(
self
,
conn
,
min_offset
,
max_offset
,
uuid
):
...
...
neo/admin/handler.py
View file @
8eb14b01
...
...
@@ -106,11 +106,6 @@ class MasterEventHandler(EventHandler):
def
answerClusterState
(
self
,
conn
,
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
):
self
.
app
.
pt
.
update
(
ptid
,
cell_list
,
self
.
app
.
nm
)
...
...
@@ -125,8 +120,6 @@ class MasterEventHandler(EventHandler):
def
notifyClusterInformation
(
self
,
conn
,
cluster_state
):
self
.
app
.
cluster_state
=
cluster_state
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
self
.
app
.
nm
.
update
(
node_list
)
class
MasterRequestEventHandler
(
EventHandler
):
""" This class handle all answer from primary master node"""
...
...
neo/client/app.py
View file @
8eb14b01
...
...
@@ -240,10 +240,10 @@ class Application(ThreadedApplication):
self
.
notifications_handler
,
node
=
self
.
trying_master_node
,
dispatcher
=
self
.
dispatcher
)
p
=
Packets
.
RequestIdentification
(
NodeTypes
.
CLIENT
,
self
.
uuid
,
None
,
self
.
name
,
None
)
try
:
ask
(
conn
,
Packets
.
RequestIdentification
(
NodeTypes
.
CLIENT
,
self
.
uuid
,
None
,
self
.
name
),
handler
=
handler
)
ask
(
conn
,
p
,
handler
=
handler
)
except
ConnectionClosed
:
continue
# If we reached the primary master node, mark as connected
...
...
@@ -256,7 +256,6 @@ class Application(ThreadedApplication):
# operational. Might raise ConnectionClosed so that the new
# primary can be looked-up again.
logging
.
info
(
'Initializing from master'
)
ask
(
conn
,
Packets
.
AskNodeInformation
(),
handler
=
handler
)
ask
(
conn
,
Packets
.
AskPartitionTable
(),
handler
=
handler
)
ask
(
conn
,
Packets
.
AskLastTransaction
(),
handler
=
handler
)
if
self
.
pt
.
operational
():
...
...
neo/client/handlers/master.py
View file @
8eb14b01
...
...
@@ -30,6 +30,16 @@ class PrimaryBootstrapHandler(AnswerBaseHandler):
self
.
app
.
trying_master_node
=
None
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
,
num_replicas
,
your_uuid
,
primary
,
known_master_list
):
app
=
self
.
app
...
...
@@ -77,27 +87,13 @@ class PrimaryBootstrapHandler(AnswerBaseHandler):
raise
ProtocolError
(
'No UUID supplied'
)
app
.
uuid
=
your_uuid
logging
.
info
(
'Got an UUID:
%
s'
,
dump
(
app
.
uuid
))
app
.
id_timestamp
=
None
# Always create partition table
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
):
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
ltid
=
packet
.
decode
()[
0
]
if
app
.
last_tid
!=
ltid
:
# Either we're connecting or we already know the last tid
# via invalidations.
...
...
@@ -124,15 +120,15 @@ class PrimaryNotificationsHandler(MTEventHandler):
db
=
app
.
getDB
()
db
is
None
or
db
.
invalidateCache
()
app
.
last_tid
=
ltid
elif
type
(
packet
)
is
Packets
.
AnswerTransactionFinished
:
def
answerTransactionFinished
(
self
,
conn
,
_
,
tid
,
callback
,
cache_dict
):
app
=
self
.
app
app
.
last_tid
=
tid
=
packet
.
decode
()[
1
]
callback
=
kw
.
pop
(
'callback'
)
app
.
last_tid
=
tid
# Update cache
cache
=
app
.
_cache
app
.
_cache_lock_acquire
()
try
:
for
oid
,
data
in
kw
.
pop
(
'cache_dict'
)
.
iteritems
():
for
oid
,
data
in
cache_dict
.
iteritems
():
# Update ex-latest value in cache
cache
.
invalidate
(
oid
,
tid
)
if
data
is
not
None
:
...
...
@@ -142,7 +138,6 @@ class PrimaryNotificationsHandler(MTEventHandler):
callback
(
tid
)
finally
:
app
.
_cache_lock_release
()
MTEventHandler
.
packetReceived
(
self
,
conn
,
packet
,
kw
)
def
connectionClosed
(
self
,
conn
):
app
=
self
.
app
...
...
@@ -185,13 +180,14 @@ class PrimaryNotificationsHandler(MTEventHandler):
self
.
app
.
pt
.
update
(
ptid
,
cell_list
,
self
.
app
.
nm
)
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
nm
=
self
.
app
.
nm
nm
.
update
(
node_list
)
super
(
PrimaryNotificationsHandler
,
self
)
.
notifyNodeInformation
(
conn
,
node_list
)
# XXX: 'update' automatically closes DOWN nodes. Do we really want
# to do the same thing for nodes in other non-running states ?
for
node_type
,
addr
,
uuid
,
state
in
node_list
:
if
state
!=
NodeStates
.
RUNNING
:
node
=
nm
.
getByUUID
(
uuid
)
getByUUID
=
self
.
app
.
nm
.
getByUUID
for
node
in
node_list
:
if
node
[
3
]
!=
NodeStates
.
RUNNING
:
node
=
getByUUID
(
node
[
2
])
if
node
and
node
.
isConnected
():
node
.
getConnection
()
.
close
()
...
...
neo/client/handlers/storage.py
View file @
8eb14b01
...
...
@@ -41,14 +41,6 @@ class StorageEventHandler(MTEventHandler):
self
.
app
.
cp
.
removeConnection
(
node
)
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
,
uuid
,
num_partitions
,
num_replicas
,
your_uuid
,
primary
,
master_list
):
...
...
@@ -57,6 +49,13 @@ class StorageBootstrapHandler(AnswerBaseHandler):
primary
,
self
.
app
.
master_conn
)
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
):
""" Handle all messages related to ZODB operations """
...
...
neo/client/pool.py
View file @
8eb14b01
...
...
@@ -57,7 +57,7 @@ class ConnectionPool(object):
conn
=
MTClientConnection
(
app
,
app
.
storage_event_handler
,
node
,
dispatcher
=
app
.
dispatcher
)
p
=
Packets
.
RequestIdentification
(
NodeTypes
.
CLIENT
,
app
.
uuid
,
None
,
app
.
name
)
app
.
uuid
,
None
,
app
.
name
,
app
.
id_timestamp
)
try
:
app
.
_ask
(
conn
,
p
,
handler
=
app
.
storage_bootstrap_handler
)
except
ConnectionClosed
:
...
...
neo/lib/bootstrap.py
View file @
8eb14b01
...
...
@@ -26,7 +26,7 @@ class BootstrapManager(EventHandler):
"""
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
primary master node, connect to it then returns when the master node
...
...
@@ -35,12 +35,12 @@ class BootstrapManager(EventHandler):
self
.
primary
=
None
self
.
server
=
server
self
.
node_type
=
node_type
self
.
uuid
=
uuid
self
.
name
=
name
self
.
num_replicas
=
None
self
.
num_partitions
=
None
self
.
current
=
None
uuid
=
property
(
lambda
self
:
self
.
app
.
uuid
)
def
announcePrimary
(
self
,
conn
):
# We found the primary master early enough to be notified of election
# end. Lucky. Anyway, we must carry on with identification request, so
...
...
@@ -55,7 +55,7 @@ class BootstrapManager(EventHandler):
EventHandler
.
connectionCompleted
(
self
,
conn
)
self
.
current
.
setRunning
()
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
):
"""
...
...
@@ -106,8 +106,9 @@ class BootstrapManager(EventHandler):
self
.
num_replicas
=
num_replicas
if
self
.
uuid
!=
your_uuid
:
# 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
))
self
.
app
.
id_timestamp
=
None
self
.
accepted
=
True
def
getPrimaryConnection
(
self
):
...
...
@@ -141,8 +142,4 @@ class BootstrapManager(EventHandler):
continue
# still processing
poll
(
1
)
return
(
self
.
current
,
conn
,
self
.
uuid
,
self
.
num_partitions
,
self
.
num_replicas
)
return
self
.
current
,
conn
,
self
.
num_partitions
,
self
.
num_replicas
neo/lib/handler.py
View file @
8eb14b01
...
...
@@ -165,6 +165,10 @@ class EventHandler(object):
return
conn
.
close
()
def
notifyNodeInformation
(
self
,
conn
,
node_list
):
app
=
self
.
app
app
.
nm
.
update
(
app
,
node_list
)
def
ping
(
self
,
conn
):
conn
.
answer
(
Packets
.
Pong
())
...
...
@@ -227,6 +231,9 @@ class MTEventHandler(EventHandler):
def
packetReceived
(
self
,
conn
,
packet
,
kw
=
{}):
"""Redirect all received packet to dispatcher thread."""
if
packet
.
isResponse
():
if
packet
.
poll_thread
:
self
.
dispatch
(
conn
,
packet
,
kw
)
kw
=
{}
if
not
(
self
.
dispatcher
.
dispatch
(
conn
,
packet
.
getId
(),
packet
,
kw
)
or
type
(
packet
)
is
Packets
.
Pong
):
raise
ProtocolError
(
'Unexpected response packet from
%
r:
%
r'
...
...
@@ -254,3 +261,6 @@ class AnswerBaseHandler(EventHandler):
packetReceived
=
unexpectedInAnswerHandler
peerBroken
=
unexpectedInAnswerHandler
protocolError
=
unexpectedInAnswerHandler
def
acceptIdentification
(
*
args
):
pass
neo/lib/node.py
View file @
8eb14b01
...
...
@@ -27,6 +27,7 @@ class Node(object):
_connection
=
None
_identified
=
False
id_timestamp
=
None
def
__init__
(
self
,
manager
,
address
=
None
,
uuid
=
None
,
state
=
NodeStates
.
UNKNOWN
):
...
...
@@ -172,7 +173,8 @@ class Node(object):
def
asTuple
(
self
):
""" Returned tuple is intended to be used in protocol encoders """
return
(
self
.
getType
(),
self
.
_address
,
self
.
_uuid
,
self
.
_state
)
return
(
self
.
getType
(),
self
.
_address
,
self
.
_uuid
,
self
.
_state
,
self
.
id_timestamp
)
def
__gt__
(
self
,
node
):
# sort per UUID if defined
...
...
@@ -348,9 +350,11 @@ class NodeManager(object):
""" Return the node that match with a given address """
return
self
.
_address_dict
.
get
(
address
,
None
)
def
getByUUID
(
self
,
uuid
):
def
getByUUID
(
self
,
uuid
,
*
id_timestamp
):
""" Return the node that match with a given UUID """
return
self
.
_uuid_dict
.
get
(
uuid
,
None
)
node
=
self
.
_uuid_dict
.
get
(
uuid
)
if
not
id_timestamp
or
node
and
(
node
.
id_timestamp
,)
==
id_timestamp
:
return
node
def
_createNode
(
self
,
klass
,
address
=
None
,
uuid
=
None
,
**
kw
):
by_address
=
self
.
getByAddress
(
address
)
...
...
@@ -386,8 +390,9 @@ class NodeManager(object):
def
createFromNodeType
(
self
,
node_type
,
**
kw
):
return
self
.
_createNode
(
NODE_TYPE_MAPPING
[
node_type
],
**
kw
)
def
update
(
self
,
node_list
):
for
node_type
,
addr
,
uuid
,
state
in
node_list
:
def
update
(
self
,
app
,
node_list
):
node_set
=
self
.
_node_set
.
copy
()
if
app
.
id_timestamp
is
None
else
None
for
node_type
,
addr
,
uuid
,
state
,
id_timestamp
in
node_list
:
# This should be done here (although klass might not be used in this
# iteration), as it raises if type is not valid.
klass
=
NODE_TYPE_MAPPING
[
node_type
]
...
...
@@ -397,14 +402,14 @@ class NodeManager(object):
node_by_addr
=
self
.
getByAddress
(
addr
)
node
=
node_by_uuid
or
node_by_addr
log_args
=
node_type
,
uuid_str
(
uuid
),
addr
,
state
log_args
=
node_type
,
uuid_str
(
uuid
),
addr
,
state
,
id_timestamp
if
node
is
None
:
if
state
==
NodeStates
.
DOWN
:
logging
.
debug
(
'NOT creating node
%
s
%
s
%
s
%
s'
,
*
log_args
)
else
:
node
=
self
.
_createNode
(
klass
,
address
=
addr
,
uuid
=
uuid
,
state
=
state
)
logging
.
debug
(
'creating node
%
r'
,
node
)
logging
.
debug
(
'NOT creating node
%
s
%
s
%
s
%
s
%
s
'
,
*
log_args
)
continue
node
=
self
.
_createNode
(
klass
,
address
=
addr
,
uuid
=
uuid
,
state
=
state
)
logging
.
debug
(
'creating node
%
r'
,
node
)
else
:
assert
isinstance
(
node
,
klass
),
'node
%
r is not '
\
'of expected type:
%
r'
%
(
node
,
klass
)
...
...
@@ -414,7 +419,7 @@ class NodeManager(object):
'node_by_addr (
%
r)'
%
(
node_by_uuid
,
node_by_addr
)
if
state
==
NodeStates
.
DOWN
:
logging
.
debug
(
'dropping node
%
r (
%
r), found with
%
s '
'
%
s
%
s
%
s'
,
node
,
node
.
isConnected
(),
*
log_args
)
'
%
s
%
s
%
s
%
s
'
,
node
,
node
.
isConnected
(),
*
log_args
)
if
node
.
isConnected
():
# Cut this connection, node removed by handler.
# It's important for a storage to disconnect nodes that
...
...
@@ -424,12 +429,20 @@ class NodeManager(object):
# partition table upon disconnection.
node
.
getConnection
()
.
close
()
self
.
remove
(
node
)
else
:
logging
.
debug
(
'updating node
%
r to
%
s
%
s
%
s
%
s'
,
node
,
*
log_args
)
node
.
setUUID
(
uuid
)
node
.
setAddress
(
addr
)
node
.
setState
(
state
)
continue
logging
.
debug
(
'updating node
%
r to
%
s
%
s
%
s
%
s
%
s'
,
node
,
*
log_args
)
node
.
setUUID
(
uuid
)
node
.
setAddress
(
addr
)
node
.
setState
(
state
)
node
.
id_timestamp
=
id_timestamp
if
app
.
uuid
==
uuid
:
app
.
id_timestamp
=
id_timestamp
if
node_set
:
# For the first notification, we receive a full list of nodes from
# the master. Remove all unknown nodes from a previous connection.
for
node
in
node_set
-
self
.
_node_set
:
self
.
remove
(
node
)
self
.
log
()
def
log
(
self
):
...
...
neo/lib/protocol.py
View file @
8eb14b01
...
...
@@ -20,7 +20,7 @@ import traceback
from
cStringIO
import
StringIO
from
struct
import
Struct
PROTOCOL_VERSION
=
7
PROTOCOL_VERSION
=
8
# Size restrictions.
MIN_PACKET_SIZE
=
10
...
...
@@ -234,6 +234,7 @@ class Packet(object):
_code
=
None
_fmt
=
None
_id
=
None
poll_thread
=
False
def
__init__
(
self
,
*
args
,
**
kw
):
assert
self
.
_code
is
not
None
,
"Packet class not registered"
...
...
@@ -594,6 +595,13 @@ class PTID(PItem):
# same definition, for now
POID
=
PTID
class
PFloat
(
PStructItemOrNone
):
"""
A float number (8-bytes length)
"""
_fmt
=
'!d'
_None
=
'
\xff
'
*
8
# common definitions
PFEmpty
=
PStruct
(
'no_content'
)
...
...
@@ -607,6 +615,7 @@ PFNodeList = PList('node_list',
PAddress
(
'address'
),
PUUID
(
'uuid'
),
PFNodeState
,
PFloat
(
'id_timestamp'
),
),
)
...
...
@@ -680,6 +689,7 @@ class RequestIdentification(Packet):
Request a node identification. This must be the first packet for any
connection. Any -> Any.
"""
poll_thread
=
True
_fmt
=
PStruct
(
'request_identification'
,
PProtocol
(
'protocol_version'
),
...
...
@@ -687,6 +697,7 @@ class RequestIdentification(Packet):
PUUID
(
'uuid'
),
PAddress
(
'address'
),
PString
(
'name'
),
PFloat
(
'id_timestamp'
),
)
_answer
=
PStruct
(
'accept_identification'
,
...
...
@@ -867,6 +878,8 @@ class FinishTransaction(Packet):
Finish a transaction. C -> PM.
Answer when a transaction is finished. PM -> C.
"""
poll_thread
=
True
_fmt
=
PStruct
(
'ask_finish_transaction'
,
PTID
(
'tid'
),
PFOidList
,
...
...
@@ -1152,12 +1165,6 @@ class NotifyNodeInformation(Packet):
PFNodeList
,
)
class
NodeInformation
(
Packet
):
"""
Ask node information
"""
_answer
=
PFEmpty
class
SetClusterState
(
Packet
):
"""
Set the cluster state
...
...
@@ -1373,6 +1380,7 @@ class LastTransaction(Packet):
Answer last committed TID.
M -> C
"""
poll_thread
=
True
_answer
=
PStruct
(
'answer_last_transaction'
,
PTID
(
'tid'
),
...
...
@@ -1521,6 +1529,7 @@ def register(request, ignore_when_closed=None):
# build a class for the answer
answer
=
type
(
'Answer
%
s'
%
(
request
.
__name__
,
),
(
Packet
,
),
{})
answer
.
_fmt
=
request
.
_answer
answer
.
poll_thread
=
request
.
poll_thread
# compute the answer code
code
=
code
|
RESPONSE_MASK
answer
.
_request
=
request
...
...
@@ -1673,8 +1682,6 @@ class Packets(dict):
AddPendingNodes
,
ignore_when_closed
=
False
)
TweakPartitionTable
=
register
(
TweakPartitionTable
,
ignore_when_closed
=
False
)
AskNodeInformation
,
AnswerNodeInformation
=
register
(
NodeInformation
)
SetClusterState
=
register
(
SetClusterState
,
ignore_when_closed
=
False
)
NotifyClusterInformation
=
register
(
...
...
neo/lib/threaded_app.py
View file @
8eb14b01
...
...
@@ -43,6 +43,8 @@ class ThreadContainer(threading.local):
class
ThreadedApplication
(
BaseApplication
):
"""The client node application."""
uuid
=
None
def
__init__
(
self
,
master_nodes
,
name
,
**
kw
):
super
(
ThreadedApplication
,
self
)
.
__init__
(
**
kw
)
self
.
poll_thread
=
threading
.
Thread
(
target
=
self
.
run
,
name
=
name
)
...
...
@@ -56,8 +58,6 @@ class ThreadedApplication(BaseApplication):
for
address
in
master_nodes
:
self
.
nm
.
createMaster
(
address
=
address
)
# no self-assigned UUID, primary master will supply us one
self
.
uuid
=
None
# Internal attribute distinct between thread
self
.
_thread_container
=
ThreadContainer
()
app_set
.
add
(
self
)
# to register self.on_log
...
...
neo/master/app.py
View file @
8eb14b01
...
...
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import
sys
,
weakref
from
collections
import
defaultdict
from
time
import
time
from
neo.lib
import
logging
...
...
@@ -44,7 +45,6 @@ class Application(BaseApplication):
last_transaction
=
ZERO_TID
backup_tid
=
None
backup_app
=
None
uuid
=
None
truncate_tid
=
None
def
__init__
(
self
,
config
):
...
...
@@ -79,9 +79,7 @@ class Application(BaseApplication):
self
.
primary_master_node
=
None
self
.
cluster_state
=
None
uuid
=
config
.
getUUID
()
if
uuid
:
self
.
uuid
=
uuid
self
.
uuid
=
config
.
getUUID
()
# election related data
self
.
unconnected_master_node_set
=
set
()
...
...
@@ -227,19 +225,20 @@ class Application(BaseApplication):
Broadcast changes for a set a nodes
Send only one packet per connection to reduce bandwidth
"""
node_dict
=
{}
node_dict
=
defaultdict
(
list
)
# group modified nodes by destination node type
for
node
in
node_list
:
node_info
=
node
.
asTuple
()
def
assign_for_notification
(
node_type
):
# helper function
node_dict
.
setdefault
(
node_type
,
[])
.
append
(
node_info
)
if
node
.
isMaster
()
or
node
.
isStorage
():
# client get notifications for master and storage only
assign_for_notification
(
NodeTypes
.
CLIENT
)
if
node
.
isMaster
()
or
node
.
isStorage
()
or
node
.
isClient
():
assign_for_notification
(
NodeTypes
.
STORAGE
)
assign_for_notification
(
NodeTypes
.
ADMIN
)
if
node
.
isAdmin
():
continue
node_dict
[
NodeTypes
.
ADMIN
]
.
append
(
node_info
)
node_dict
[
NodeTypes
.
STORAGE
]
.
append
(
node_info
)
if
node
.
isClient
():
continue
node_dict
[
NodeTypes
.
CLIENT
]
.
append
(
node_info
)
if
node
.
isStorage
():
continue
node_dict
[
NodeTypes
.
MASTER
]
.
append
(
node_info
)
# send at most one non-empty notification packet per node
for
node
in
self
.
nm
.
getIdentifiedList
():
...
...
@@ -498,7 +497,7 @@ class Application(BaseApplication):
conn
.
setHandler
(
handler
)
conn
.
notify
(
Packets
.
NotifyNodeInformation
(((
node
.
getType
(),
node
.
getAddress
(),
node
.
getUUID
(),
NodeStates
.
TEMPORARILY_DOWN
),)))
NodeStates
.
TEMPORARILY_DOWN
,
None
),)))
conn
.
abort
()
elif
conn
.
pending
():
conn
.
abort
()
...
...
neo/master/backup_app.py
View file @
8eb14b01
...
...
@@ -65,6 +65,7 @@ There is no UUID conflict between the 2 clusters:
class
BackupApplication
(
object
):
pt
=
None
uuid
=
None
def
__init__
(
self
,
app
,
name
,
master_addresses
):
self
.
app
=
weakref
.
proxy
(
app
)
...
...
@@ -92,7 +93,7 @@ class BackupApplication(object):
pt
=
app
.
pt
while
True
:
app
.
changeClusterState
(
ClusterStates
.
STARTING_BACKUP
)
bootstrap
=
BootstrapManager
(
self
,
self
.
name
,
NodeTypes
.
CLIENT
)
bootstrap
=
BootstrapManager
(
self
,
NodeTypes
.
CLIENT
)
# {offset -> node}
self
.
primary_partition_dict
=
{}
# [[tid]]
...
...
@@ -105,7 +106,7 @@ class BackupApplication(object):
else
:
break
poll
(
1
)
node
,
conn
,
uuid
,
num_partitions
,
num_replicas
=
\
node
,
conn
,
num_partitions
,
num_replicas
=
\
bootstrap
.
getPrimaryConnection
()
try
:
app
.
changeClusterState
(
ClusterStates
.
BACKINGUP
)
...
...
@@ -114,7 +115,6 @@ class BackupApplication(object):
raise
RuntimeError
(
"inconsistent number of partitions"
)
self
.
pt
=
PartitionTable
(
num_partitions
,
num_replicas
)
conn
.
setHandler
(
BackupHandler
(
self
))
conn
.
ask
(
Packets
.
AskNodeInformation
())
conn
.
ask
(
Packets
.
AskPartitionTable
())
conn
.
ask
(
Packets
.
AskLastTransaction
())
# debug variable to log how big 'tid_list' can be.
...
...
neo/master/handlers/__init__.py
View file @
8eb14b01
...
...
@@ -18,7 +18,7 @@ from neo.lib import logging
from
neo.lib.exception
import
StoppedOperation
from
neo.lib.handler
import
EventHandler
from
neo.lib.protocol
import
(
uuid_str
,
NodeTypes
,
NodeStates
,
Packets
,
BrokenNodeDisallowedError
,
BrokenNodeDisallowedError
,
ProtocolError
,
)
class
MasterHandler
(
EventHandler
):
...
...
@@ -27,18 +27,19 @@ class MasterHandler(EventHandler):
def
connectionCompleted
(
self
,
conn
,
new
=
None
):
if
new
is
None
:
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
)
app
=
self
.
app
node
=
app
.
nm
.
getByUUID
(
uuid
)
if
node
:
assert
node_type
is
not
NodeTypes
.
MASTER
or
node
.
getAddress
()
in
(
address
,
None
),
(
node
,
address
)
if
node_type
is
NodeTypes
.
MASTER
and
not
(
None
!=
address
==
node
.
getAddress
()):
raise
ProtocolError
if
node
.
isBroken
():
raise
BrokenNodeDisallowedError
else
:
node
=
app
.
nm
.
getByAddress
(
address
)
peer_uuid
=
self
.
_setupNode
(
conn
,
node_type
,
uuid
,
address
,
node
)
if
app
.
primary
:
primary_address
=
app
.
server
...
...
@@ -89,10 +90,6 @@ class MasterHandler(EventHandler):
node_list
.
extend
(
n
.
asTuple
()
for
n
in
nm
.
getStorageList
())
conn
.
notify
(
Packets
.
NotifyNodeInformation
(
node_list
))
def
askNodeInformation
(
self
,
conn
):
self
.
_notifyNodeInformation
(
conn
)
conn
.
answer
(
Packets
.
AnswerNodeInformation
())
def
askPartitionTable
(
self
,
conn
):
pt
=
self
.
app
.
pt
conn
.
answer
(
Packets
.
AnswerPartitionTable
(
pt
.
getID
(),
pt
.
getRowList
()))
...
...
neo/master/handlers/backup.py
View file @
8eb14b01
...
...
@@ -31,12 +31,6 @@ class BackupHandler(EventHandler):
def
notifyPartitionChanges
(
self
,
conn
,
ptid
,
cell_list
):
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
)
def
answerLastTransaction
(
self
,
conn
,
tid
):
app
=
self
.
app
if
tid
!=
ZERO_TID
:
...
...
neo/master/handlers/client.py
View file @
8eb14b01
...
...
@@ -31,14 +31,12 @@ class ClientServiceHandler(MasterHandler):
app
.
broadcastNodesInformation
([
node
])
app
.
nm
.
remove
(
node
)
def
askNodeInformation
(
self
,
conn
):
# send informations about master and storages only
def
_notifyNodeInformation
(
self
,
conn
):
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
.
getStorageList
())
conn
.
notify
(
Packets
.
NotifyNodeInformation
(
node_list
))
conn
.
answer
(
Packets
.
AnswerNodeInformation
())
def
askBeginTransaction
(
self
,
conn
,
tid
):
"""
...
...
neo/master/handlers/election.py
View file @
8eb14b01
...
...
@@ -23,6 +23,9 @@ from . import MasterHandler
class
BaseElectionHandler
(
EventHandler
):
def
_notifyNodeInformation
(
self
,
conn
):
pass
def
reelectPrimary
(
self
,
conn
):
raise
ElectionFailure
,
'reelection requested'
...
...
@@ -53,6 +56,11 @@ class BaseElectionHandler(EventHandler):
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
):
addr
=
conn
.
getAddress
()
node
=
self
.
app
.
nm
.
getByAddress
(
addr
)
...
...
@@ -68,6 +76,7 @@ class ClientElectionHandler(BaseElectionHandler):
app
.
uuid
,
app
.
server
,
app
.
name
,
None
,
))
super
(
ClientElectionHandler
,
self
)
.
connectionCompleted
(
conn
)
...
...
@@ -126,8 +135,8 @@ class ServerElectionHandler(BaseElectionHandler, MasterHandler):
logging
.
info
(
'reject a connection from a non-master'
)
raise
NotReadyError
if
node
is
None
:
node
=
app
.
nm
.
createMaster
(
address
=
address
)
if
node
is
None
is
app
.
nm
.
getByAddress
(
address
)
:
app
.
nm
.
createMaster
(
address
=
address
)
self
.
elect
(
conn
,
address
)
return
uuid
...
...
neo/master/handlers/identification.py
View file @
8eb14b01
...
...
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from
time
import
time
from
neo.lib
import
logging
from
neo.lib.protocol
import
ClusterStates
,
NodeStates
,
NodeTypes
,
\
NotReadyError
,
ProtocolError
,
uuid_str
...
...
@@ -30,18 +31,32 @@ class IdentificationHandler(MasterHandler):
def
_setupNode
(
self
,
conn
,
node_type
,
uuid
,
address
,
node
):
app
=
self
.
app