Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
Willemt Raft
Commits
1ac903b0
Commit
1ac903b0
authored
Jul 28, 2015
by
Willem Thiart
Browse files
Added raft_add_peer
parent
31ca2e7b
Changes
4
Show whitespace changes
Inline
Side-by-side
include/raft.h
View file @
1ac903b0
...
@@ -212,7 +212,27 @@ void raft_set_callbacks(raft_server_t* me, raft_cbs_t* funcs, void* udata);
...
@@ -212,7 +212,27 @@ void raft_set_callbacks(raft_server_t* me, raft_cbs_t* funcs, void* udata);
* @param nodes Array of nodes. End of array is marked by NULL entry
* @param nodes Array of nodes. End of array is marked by NULL entry
* @param my_idx Index of the node that refers to this Raft server */
* @param my_idx Index of the node that refers to this Raft server */
void
raft_set_configuration
(
raft_server_t
*
me_
,
void
raft_set_configuration
(
raft_server_t
*
me_
,
raft_node_configuration_t
*
nodes
,
int
my_idx
);
raft_node_configuration_t
*
nodes
,
int
my_idx
)
__attribute__
((
deprecated
));
/**
* Add peer
*
* NOTE: This library does not yet support membership changes.
* Once raft_periodic has been run this will fail.
*
* NOTE: The order this call is made is important.
* This call MUST be made in the same order as the other raft peers.
* This is because the node ID is assigned depending on when this call is made
*
* @param udata The user data for the node.
* This is obtained using raft_node_get_udata.
* Examples of what this could be:
* - void* pointing to implementor's networking data
* - a (IP,Port) tuple
* @param is_self True if this "peer" is this server
* @return 0 on success; otherwise -1 */
int
raft_add_peer
(
raft_server_t
*
me_
,
void
*
udata
,
int
is_self
);
/**
/**
* Set election timeout
* Set election timeout
...
@@ -337,6 +357,10 @@ int raft_node_is_leader(raft_node_t* node);
...
@@ -337,6 +357,10 @@ int raft_node_is_leader(raft_node_t* node);
* @return the node's next index */
* @return the node's next index */
int
raft_node_get_next_idx
(
raft_node_t
*
node
);
int
raft_node_get_next_idx
(
raft_node_t
*
node
);
/**
* @return this node's user data */
void
*
raft_node_get_udata
(
raft_node_t
*
me_
);
/**
/**
* @param idx The entry's index
* @param idx The entry's index
* @return entry from index */
* @return entry from index */
...
...
src/raft_server.c
View file @
1ac903b0
...
@@ -511,6 +511,23 @@ void raft_set_configuration(raft_server_t* me_,
...
@@ -511,6 +511,23 @@ void raft_set_configuration(raft_server_t* me_,
me
->
nodeid
=
my_idx
;
me
->
nodeid
=
my_idx
;
}
}
int
raft_add_peer
(
raft_server_t
*
me_
,
void
*
udata
,
int
is_self
)
{
raft_server_private_t
*
me
=
(
raft_server_private_t
*
)
me_
;
/* TODO: does not yet support dynamic membership changes */
if
(
me
->
current_term
!=
0
&&
me
->
timeout_elapsed
!=
0
&&
me
->
election_timeout
!=
0
)
return
-
1
;
me
->
num_nodes
++
;
me
->
nodes
=
(
raft_node_t
*
)
realloc
(
me
->
nodes
,
sizeof
(
raft_node_t
*
)
*
me
->
num_nodes
);
me
->
nodes
[
me
->
num_nodes
-
1
]
=
raft_node_new
(
udata
);
me
->
votes_for_me
=
(
int
*
)
realloc
(
me
->
votes_for_me
,
me
->
num_nodes
*
sizeof
(
int
));
if
(
is_self
)
me
->
nodeid
=
me
->
num_nodes
-
1
;
return
0
;
}
int
raft_get_nvotes_for_me
(
raft_server_t
*
me_
)
int
raft_get_nvotes_for_me
(
raft_server_t
*
me_
)
{
{
raft_server_private_t
*
me
=
(
raft_server_private_t
*
)
me_
;
raft_server_private_t
*
me
=
(
raft_server_private_t
*
)
me_
;
...
...
tests/test_scenario.c
View file @
1ac903b0
...
@@ -13,25 +13,21 @@
...
@@ -13,25 +13,21 @@
void
TestRaft_scenario_leader_appears
(
CuTest
*
tc
)
void
TestRaft_scenario_leader_appears
(
CuTest
*
tc
)
{
{
int
i
,
j
;
unsigned
long
i
,
j
;
raft_server_t
*
r
[
3
];
raft_server_t
*
r
[
3
];
void
*
sender
[
3
];
void
*
sender
[
3
];
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
(
void
*
)
3
},
{
NULL
}
};
senders_new
();
senders_new
();
for
(
j
=
0
;
j
<
3
;
j
++
)
for
(
j
=
0
;
j
<
3
;
j
++
)
{
{
r
[
j
]
=
raft_new
();
r
[
j
]
=
raft_new
();
sender
[
j
]
=
sender_new
(
cfg
[
j
].
udata_address
);
sender
[
j
]
=
sender_new
(
(
void
*
)
j
);
sender_set_raft
(
sender
[
j
],
r
[
j
]);
sender_set_raft
(
sender
[
j
],
r
[
j
]);
raft_set_election_timeout
(
r
[
j
],
500
);
raft_set_election_timeout
(
r
[
j
],
500
);
raft_set_configuration
(
r
[
j
],
cfg
,
j
);
raft_add_peer
(
r
[
j
],
(
void
*
)
1
,
j
==
0
);
raft_add_peer
(
r
[
j
],
(
void
*
)
2
,
j
==
1
);
raft_add_peer
(
r
[
j
],
(
void
*
)
3
,
j
==
2
);
raft_set_callbacks
(
r
[
j
],
raft_set_callbacks
(
r
[
j
],
&
((
raft_cbs_t
)
{
&
((
raft_cbs_t
)
{
.
send_requestvote
=
sender_requestvote
,
.
send_requestvote
=
sender_requestvote
,
...
...
tests/test_server.c
View file @
1ac903b0
...
@@ -314,34 +314,18 @@ TestRaft_server_election_timeout_sets_to_zero_when_elapsed_time_greater_than_tim
...
@@ -314,34 +314,18 @@ TestRaft_server_election_timeout_sets_to_zero_when_elapsed_time_greater_than_tim
void
TestRaft_server_cfg_sets_num_nodes
(
CuTest
*
tc
)
void
TestRaft_server_cfg_sets_num_nodes
(
CuTest
*
tc
)
{
{
void
*
r
;
void
*
r
=
raft_new
();
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
/* 2 nodes */
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
CuAssertTrue
(
tc
,
2
==
raft_get_num_nodes
(
r
));
CuAssertTrue
(
tc
,
2
==
raft_get_num_nodes
(
r
));
}
}
void
TestRaft_server_cant_get_node_we_dont_have
(
CuTest
*
tc
)
void
TestRaft_server_cant_get_node_we_dont_have
(
CuTest
*
tc
)
{
{
void
*
r
;
void
*
r
=
raft_new
();
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
/* 2 nodes */
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
CuAssertTrue
(
tc
,
NULL
!=
raft_get_node
(
r
,
0
));
CuAssertTrue
(
tc
,
NULL
!=
raft_get_node
(
r
,
0
));
CuAssertTrue
(
tc
,
NULL
!=
raft_get_node
(
r
,
1
));
CuAssertTrue
(
tc
,
NULL
!=
raft_get_node
(
r
,
1
));
...
@@ -378,15 +362,9 @@ TestRaft_server_dont_increase_votes_for_me_when_receive_request_vote_response_is
...
@@ -378,15 +362,9 @@ TestRaft_server_dont_increase_votes_for_me_when_receive_request_vote_response_is
void
*
r
;
void
*
r
;
msg_requestvote_response_t
rvr
;
msg_requestvote_response_t
rvr
;
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_current_term
(
r
,
1
);
raft_set_current_term
(
r
,
1
);
CuAssertTrue
(
tc
,
0
==
raft_get_nvotes_for_me
(
r
));
CuAssertTrue
(
tc
,
0
==
raft_get_nvotes_for_me
(
r
));
...
@@ -404,15 +382,9 @@ void TestRaft_server_increase_votes_for_me_when_receive_request_vote_response(
...
@@ -404,15 +382,9 @@ void TestRaft_server_increase_votes_for_me_when_receive_request_vote_response(
void
*
r
;
void
*
r
;
msg_requestvote_response_t
rvr
;
msg_requestvote_response_t
rvr
;
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_current_term
(
r
,
1
);
raft_set_current_term
(
r
,
1
);
CuAssertTrue
(
tc
,
0
==
raft_get_nvotes_for_me
(
r
));
CuAssertTrue
(
tc
,
0
==
raft_get_nvotes_for_me
(
r
));
...
@@ -436,15 +408,9 @@ void TestRaft_server_recv_requestvote_reply_false_if_term_less_than_current_term
...
@@ -436,15 +408,9 @@ void TestRaft_server_recv_requestvote_reply_false_if_term_less_than_current_term
msg_requestvote_t
rv
;
msg_requestvote_t
rv
;
msg_requestvote_response_t
rvr
;
msg_requestvote_response_t
rvr
;
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_current_term
(
r
,
2
);
raft_set_current_term
(
r
,
2
);
...
@@ -470,15 +436,9 @@ void TestRaft_server_recv_requestvote_reply_true_if_term_greater_than_or_equal_t
...
@@ -470,15 +436,9 @@ void TestRaft_server_recv_requestvote_reply_true_if_term_greater_than_or_equal_t
msg_requestvote_t
rv
;
msg_requestvote_t
rv
;
msg_requestvote_response_t
rvr
;
msg_requestvote_response_t
rvr
;
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_current_term
(
r
,
1
);
raft_set_current_term
(
r
,
1
);
...
@@ -506,16 +466,10 @@ void TestRaft_server_dont_grant_vote_if_we_didnt_vote_for_this_candidate(
...
@@ -506,16 +466,10 @@ void TestRaft_server_dont_grant_vote_if_we_didnt_vote_for_this_candidate(
msg_requestvote_t
rv
;
msg_requestvote_t
rv
;
msg_requestvote_response_t
rvr
;
msg_requestvote_response_t
rvr
;
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_vote
(
r
,
0
);
raft_vote
(
r
,
0
);
...
@@ -563,15 +517,9 @@ TestRaft_follower_recv_appendentries_reply_false_if_term_less_than_currentterm(
...
@@ -563,15 +517,9 @@ TestRaft_follower_recv_appendentries_reply_false_if_term_less_than_currentterm(
msg_appendentries_t
ae
;
msg_appendentries_t
ae
;
msg_appendentries_response_t
aer
;
msg_appendentries_response_t
aer
;
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
...
@@ -601,15 +549,9 @@ TestRaft_follower_recv_appendentries_updates_currentterm_if_term_gt_currentterm(
...
@@ -601,15 +549,9 @@ TestRaft_follower_recv_appendentries_updates_currentterm_if_term_gt_currentterm(
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
...
@@ -637,15 +579,9 @@ void TestRaft_follower_doesnt_log_after_appendentry_if_no_entries_are_specified(
...
@@ -637,15 +579,9 @@ void TestRaft_follower_doesnt_log_after_appendentry_if_no_entries_are_specified(
msg_appendentries_t
ae
;
msg_appendentries_t
ae
;
msg_appendentries_response_t
aer
;
msg_appendentries_response_t
aer
;
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_state
(
r
,
RAFT_STATE_FOLLOWER
);
raft_set_state
(
r
,
RAFT_STATE_FOLLOWER
);
...
@@ -677,15 +613,9 @@ void TestRaft_follower_increases_log_after_appendentry(CuTest * tc)
...
@@ -677,15 +613,9 @@ void TestRaft_follower_increases_log_after_appendentry(CuTest * tc)
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
...
@@ -726,19 +656,14 @@ TestRaft_follower_recv_appendentries_reply_false_if_doesnt_have_log_at_prev_log_
...
@@ -726,19 +656,14 @@ TestRaft_follower_recv_appendentries_reply_false_if_doesnt_have_log_at_prev_log_
raft_cbs_t
funcs
=
{
raft_cbs_t
funcs
=
{
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
msg_appendentries_t
ae
;
msg_appendentries_t
ae
;
msg_appendentries_response_t
aer
;
msg_appendentries_response_t
aer
;
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
/* term is different from appendentries */
/* term is different from appendentries */
...
@@ -783,15 +708,9 @@ TestRaft_follower_recv_appendentries_delete_entries_if_conflict_with_new_entries
...
@@ -783,15 +708,9 @@ TestRaft_follower_recv_appendentries_delete_entries_if_conflict_with_new_entries
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
...
@@ -851,16 +770,10 @@ void TestRaft_follower_recv_appendentries_add_new_entries_not_already_in_log(
...
@@ -851,16 +770,10 @@ void TestRaft_follower_recv_appendentries_add_new_entries_not_already_in_log(
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
r
=
raft_new
();
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_current_term
(
r
,
1
);
raft_set_current_term
(
r
,
1
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
...
@@ -895,16 +808,10 @@ void TestRaft_follower_recv_appendentries_set_commitidx_to_prevLogIdx(
...
@@ -895,16 +808,10 @@ void TestRaft_follower_recv_appendentries_set_commitidx_to_prevLogIdx(
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
msg_appendentries_t
ae
;
msg_appendentries_t
ae
;
...
@@ -948,16 +855,10 @@ void TestRaft_follower_recv_appendentries_set_commitidx_to_LeaderCommit(
...
@@ -948,16 +855,10 @@ void TestRaft_follower_recv_appendentries_set_commitidx_to_LeaderCommit(
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
msg_appendentries_t
ae
;
msg_appendentries_t
ae
;
...
@@ -995,21 +896,13 @@ void TestRaft_follower_recv_appendentries_set_commitidx_to_LeaderCommit(
...
@@ -995,21 +896,13 @@ void TestRaft_follower_recv_appendentries_set_commitidx_to_LeaderCommit(
void
TestRaft_follower_becomes_candidate_when_election_timeout_occurs
(
void
TestRaft_follower_becomes_candidate_when_election_timeout_occurs
(
CuTest
*
tc
)
CuTest
*
tc
)
{
{
void
*
r
;
void
*
r
=
raft_new
();
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
r
=
raft_new
();
/* 1 second election timeout */
/* 1 second election timeout */
raft_set_election_timeout
(
r
,
1000
);
raft_set_election_timeout
(
r
,
1000
);
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
/* 1.001 seconds have passed */
/* 1.001 seconds have passed */
raft_periodic
(
r
,
1001
);
raft_periodic
(
r
,
1001
);
...
@@ -1028,20 +921,14 @@ void TestRaft_follower_dont_grant_vote_if_candidate_has_a_less_complete_log(
...
@@ -1028,20 +921,14 @@ void TestRaft_follower_dont_grant_vote_if_candidate_has_a_less_complete_log(
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
msg_requestvote_t
rv
;
msg_requestvote_t
rv
;
msg_requestvote_response_t
rvr
;
msg_requestvote_response_t
rvr
;
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
/* request vote */
/* request vote */
/* vote indicates candidate's log is not complete compared to follower */
/* vote indicates candidate's log is not complete compared to follower */
...
@@ -1141,18 +1028,14 @@ void TestRaft_follower_becoming_candidate_requests_votes_from_other_servers(
...
@@ -1141,18 +1028,14 @@ void TestRaft_follower_becoming_candidate_requests_votes_from_other_servers(
.
send_requestvote
=
sender_requestvote
,
.
send_requestvote
=
sender_requestvote
,
.
log
=
NULL
.
log
=
NULL
};
};
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
(
void
*
)
3
},
{
NULL
}
};
msg_requestvote_t
*
rv
;
msg_requestvote_t
*
rv
;
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_add_peer
(
r
,
(
void
*
)
3
,
0
);
/* set term so we can check it gets included in the outbound message */
/* set term so we can check it gets included in the outbound message */
raft_set_current_term
(
r
,
2
);
raft_set_current_term
(
r
,
2
);
...
@@ -1182,13 +1065,6 @@ void TestRaft_candidate_election_timeout_and_no_leader_results_in_new_election(
...
@@ -1182,13 +1065,6 @@ void TestRaft_candidate_election_timeout_and_no_leader_results_in_new_election(
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
msg_requestvote_response_t
vr
;
msg_requestvote_response_t
vr
;
memset
(
&
vr
,
0
,
sizeof
(
msg_requestvote_response_t
));
memset
(
&
vr
,
0
,
sizeof
(
msg_requestvote_response_t
));
...
@@ -1198,7 +1074,8 @@ void TestRaft_candidate_election_timeout_and_no_leader_results_in_new_election(
...
@@ -1198,7 +1074,8 @@ void TestRaft_candidate_election_timeout_and_no_leader_results_in_new_election(
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_election_timeout
(
r
,
1000
);
raft_set_election_timeout
(
r
,
1000
);
...
@@ -1224,22 +1101,16 @@ void TestRaft_candidate_receives_majority_of_votes_becomes_leader(CuTest * tc)
...
@@ -1224,22 +1101,16 @@ void TestRaft_candidate_receives_majority_of_votes_becomes_leader(CuTest * tc)
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
(
void
*
)
3
},
{
(
void
*
)
4
},
{
(
void
*
)
5
},
{
NULL
}
};
msg_requestvote_response_t
vr
;
msg_requestvote_response_t
vr
;
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_add_peer
(
r
,
(
void
*
)
3
,
0
);
raft_add_peer
(
r
,
(
void
*
)
4
,
0
);
raft_add_peer
(
r
,
(
void
*
)
5
,
0
);
CuAssertTrue
(
tc
,
5
==
raft_get_num_nodes
(
r
));
CuAssertTrue
(
tc
,
5
==
raft_get_num_nodes
(
r
));
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
...
@@ -1273,19 +1144,13 @@ void TestRaft_candidate_will_not_respond_to_voterequest_if_it_has_already_voted(
...
@@ -1273,19 +1144,13 @@ void TestRaft_candidate_will_not_respond_to_voterequest_if_it_has_already_voted(
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
msg_requestvote_t
rv
;
msg_requestvote_t
rv
;
msg_requestvote_response_t
rvr
;
msg_requestvote_response_t
rvr
;
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_vote
(
r
,
0
);
raft_vote
(
r
,
0
);
...
@@ -1308,16 +1173,10 @@ void TestRaft_candidate_requestvote_includes_logidx(CuTest * tc)
...
@@ -1308,16 +1173,10 @@ void TestRaft_candidate_requestvote_includes_logidx(CuTest * tc)
};
};
msg_requestvote_t
*
rv
;
msg_requestvote_t
*
rv
;
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
99
);
raft_add_peer
(
r
,
(
void
*
)
1
,
0
);
raft_add_peer
(
r
,
(
void
*
)
2
,
1
);
raft_set_state
(
r
,
RAFT_STATE_CANDIDATE
);
raft_set_state
(
r
,
RAFT_STATE_CANDIDATE
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
...
@@ -1330,7 +1189,7 @@ void TestRaft_candidate_requestvote_includes_logidx(CuTest * tc)
...
@@ -1330,7 +1189,7 @@ void TestRaft_candidate_requestvote_includes_logidx(CuTest * tc)
CuAssertTrue
(
tc
,
3
==
rv
->
last_log_idx
);
CuAssertTrue
(
tc
,
3
==
rv
->
last_log_idx
);
CuAssertTrue
(
tc
,
5
==
rv
->
term
);
CuAssertTrue
(
tc
,
5
==
rv
->
term
);
CuAssertTrue
(
tc
,
5
==
rv
->
last_log_term
);
CuAssertTrue
(
tc
,
5
==
rv
->
last_log_term
);
CuAssertTrue
(
tc
,
99
==
rv
->
candidate_id
);
CuAssertTrue
(
tc
,
1
==
rv
->
candidate_id
);
}
}
/* Candidate 5.2 */
/* Candidate 5.2 */
...
@@ -1343,17 +1202,11 @@ void TestRaft_candidate_recv_appendentries_frm_leader_results_in_follower(
...
@@ -1343,17 +1202,11 @@ void TestRaft_candidate_recv_appendentries_frm_leader_results_in_follower(
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_state
(
r
,
RAFT_STATE_CANDIDATE
);
raft_set_state
(
r
,
RAFT_STATE_CANDIDATE
);
...
@@ -1380,20 +1233,14 @@ TestRaft_candidate_recv_appendentries_frm_invalid_leader_doesnt_result_in_follow
...
@@ -1380,20 +1233,14 @@ TestRaft_candidate_recv_appendentries_frm_invalid_leader_doesnt_result_in_follow
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
msg_appendentries_t
ae
;
msg_appendentries_t
ae
;
msg_appendentries_response_t
aer
;
msg_appendentries_response_t
aer
;
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
/* server's log is newer */
/* server's log is newer */
raft_set_current_term
(
r
,
1
);
raft_set_current_term
(
r
,
1
);
...
@@ -1445,18 +1292,12 @@ TestRaft_leader_when_becomes_leader_all_nodes_have_nextidx_equal_to_lastlog_idx_
...
@@ -1445,18 +1292,12 @@ TestRaft_leader_when_becomes_leader_all_nodes_have_nextidx_equal_to_lastlog_idx_
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
(
void
*
)
3
},
{
NULL
}
};
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_add_peer
(
r
,
(
void
*
)
3
,
0
);
/* candidate to leader */
/* candidate to leader */
raft_set_state
(
r
,
RAFT_STATE_CANDIDATE
);
raft_set_state
(
r
,
RAFT_STATE_CANDIDATE
);
...
@@ -1484,19 +1325,14 @@ void TestRaft_leader_when_it_becomes_a_leader_sends_empty_appendentries(
...
@@ -1484,19 +1325,14 @@ void TestRaft_leader_when_it_becomes_a_leader_sends_empty_appendentries(
.
log
=
NULL
.
log
=
NULL
};
};
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
(
void
*
)
3
},
{
NULL
}
};
msg_appendentries_t
*
ae
;
msg_appendentries_t
*
ae
;
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_add_peer
(
r
,
(
void
*
)
3
,
0
);
/* candidate to leader */
/* candidate to leader */
raft_set_state
(
r
,
RAFT_STATE_CANDIDATE
);
raft_set_state
(
r
,
RAFT_STATE_CANDIDATE
);
...
@@ -1519,17 +1355,11 @@ void TestRaft_leader_responds_to_entry_msg_when_entry_is_committed(CuTest * tc)
...
@@ -1519,17 +1355,11 @@ void TestRaft_leader_responds_to_entry_msg_when_entry_is_committed(CuTest * tc)
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
/* I am the leader */
/* I am the leader */
raft_set_state
(
r
,
RAFT_STATE_LEADER
);
raft_set_state
(
r
,
RAFT_STATE_LEADER
);
...
@@ -1563,19 +1393,13 @@ void TestRaft_leader_sends_appendentries_with_NextIdx_when_PrevIdx_gt_NextIdx(
...
@@ -1563,19 +1393,13 @@ void TestRaft_leader_sends_appendentries_with_NextIdx_when_PrevIdx_gt_NextIdx(
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
msg_appendentries_t
*
ae
;
msg_appendentries_t
*
ae
;
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
/* i'm leader */
/* i'm leader */
raft_set_state
(
r
,
RAFT_STATE_LEADER
);
raft_set_state
(
r
,
RAFT_STATE_LEADER
);
...
@@ -1602,19 +1426,13 @@ TestRaft_leader_retries_appendentries_with_decremented_NextIdx_log_inconsistency
...
@@ -1602,19 +1426,13 @@ TestRaft_leader_retries_appendentries_with_decremented_NextIdx_log_inconsistency
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
msg_appendentries_t
*
ae
;
msg_appendentries_t
*
ae
;
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
/* i'm leader */
/* i'm leader */
raft_set_state
(
r
,
RAFT_STATE_LEADER
);
raft_set_state
(
r
,
RAFT_STATE_LEADER
);
...
@@ -1633,13 +1451,6 @@ void TestRaft_leader_append_entry_to_log_increases_idxno(CuTest * tc)
...
@@ -1633,13 +1451,6 @@ void TestRaft_leader_append_entry_to_log_increases_idxno(CuTest * tc)
{
{
void
*
r
;
void
*
r
;
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
msg_entry_t
ety
;
msg_entry_t
ety
;
msg_entry_response_t
cr
;
msg_entry_response_t
cr
;
...
@@ -1648,7 +1459,8 @@ void TestRaft_leader_append_entry_to_log_increases_idxno(CuTest * tc)
...
@@ -1648,7 +1459,8 @@ void TestRaft_leader_append_entry_to_log_increases_idxno(CuTest * tc)
ety
.
len
=
strlen
(
"entry"
);
ety
.
len
=
strlen
(
"entry"
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_state
(
r
,
RAFT_STATE_LEADER
);
raft_set_state
(
r
,
RAFT_STATE_LEADER
);
CuAssertTrue
(
tc
,
0
==
raft_get_log_count
(
r
));
CuAssertTrue
(
tc
,
0
==
raft_get_log_count
(
r
));
...
@@ -1700,15 +1512,10 @@ TestRaft_leader_increase_commit_idx_when_majority_have_entry_and_atleast_one_new
...
@@ -1700,15 +1512,10 @@ TestRaft_leader_increase_commit_idx_when_majority_have_entry_and_atleast_one_new
};
};
msg_appendentries_response_t
aer
;
msg_appendentries_response_t
aer
;
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
/* I'm the leader */
/* I'm the leader */
...
@@ -1774,19 +1581,13 @@ void TestRaft_leader_steps_down_if_received_appendentries_is_newer_than_itself(
...
@@ -1774,19 +1581,13 @@ void TestRaft_leader_steps_down_if_received_appendentries_is_newer_than_itself(
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
msg_appendentries_t
ae
;
msg_appendentries_t
ae
;
msg_appendentries_response_t
aer
;
msg_appendentries_response_t
aer
;
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_state
(
r
,
RAFT_STATE_LEADER
);
raft_set_state
(
r
,
RAFT_STATE_LEADER
);
raft_set_current_term
(
r
,
5
);
raft_set_current_term
(
r
,
5
);
...
@@ -1811,19 +1612,13 @@ void TestRaft_leader_steps_down_if_received_appendentries_has_newer_term_than_it
...
@@ -1811,19 +1612,13 @@ void TestRaft_leader_steps_down_if_received_appendentries_has_newer_term_than_it
.
log
=
NULL
.
log
=
NULL
};
};
/* 2 nodes */
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
NULL
}
};
msg_appendentries_t
ae
;
msg_appendentries_t
ae
;
msg_appendentries_response_t
aer
;
msg_appendentries_response_t
aer
;
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_set_state
(
r
,
RAFT_STATE_LEADER
);
raft_set_state
(
r
,
RAFT_STATE_LEADER
);
raft_set_current_term
(
r
,
5
);
raft_set_current_term
(
r
,
5
);
...
@@ -1849,19 +1644,14 @@ void TestRaft_leader_sends_empty_appendentries_every_request_timeout(
...
@@ -1849,19 +1644,14 @@ void TestRaft_leader_sends_empty_appendentries_every_request_timeout(
.
log
=
NULL
.
log
=
NULL
};
};
raft_node_configuration_t
cfg
[]
=
{
{
(
void
*
)
1
},
{
(
void
*
)
2
},
{
(
void
*
)
3
},
{
NULL
}
};
msg_appendentries_t
*
ae
;
msg_appendentries_t
*
ae
;
sender
=
sender_new
(
NULL
);
sender
=
sender_new
(
NULL
);
r
=
raft_new
();
r
=
raft_new
();
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_callbacks
(
r
,
&
funcs
,
sender
);
raft_set_configuration
(
r
,
cfg
,
0
);
raft_add_peer
(
r
,
(
void
*
)
1
,
1
);
raft_add_peer
(
r
,
(
void
*
)
2
,
0
);
raft_add_peer
(
r
,
(
void
*
)
3
,
0
);
raft_set_election_timeout
(
r
,
1000
);
raft_set_election_timeout
(
r
,
1000
);
raft_set_request_timeout
(
r
,
500
);
raft_set_request_timeout
(
r
,
500
);
CuAssertTrue
(
tc
,
0
==
raft_get_timeout_elapsed
(
r
));
CuAssertTrue
(
tc
,
0
==
raft_get_timeout_elapsed
(
r
));
...
...
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