24 #ifndef GRAPHLAB_LOCAL_CHANDY_MISRA_HPP
25 #define GRAPHLAB_LOCAL_CHANDY_MISRA_HPP
27 #include <graphlab/logger/assertions.hpp>
28 #include <graphlab/parallel/pthread_tools.hpp>
29 #include <graphlab/macros_def.hpp>
32 template <
typename GraphType>
43 std::vector<unsigned char> forkset;
48 enum {OWNER_SOURCE = 0, OWNER_TARGET = 1};
49 inline unsigned char request_bit(
bool owner) {
50 return owner ? REQUEST_1 : REQUEST_0;
59 std::vector<philosopher> philosopherset;
70 inline void request_for_fork(
size_t forkid,
bool nextowner) {
71 forkset[forkid] |= request_bit(nextowner);
74 inline bool fork_owner(
size_t forkid) {
75 return forkset[forkid] & OWNER_BIT;
78 inline bool fork_dirty(
size_t forkid) {
79 return !!(forkset[forkid] & DIRTY_BIT);
82 inline void dirty_fork(
size_t forkid) {
83 forkset[forkid] |= DIRTY_BIT;
90 inline void advance_fork_state_on_lock(
size_t forkid,
94 unsigned char currentowner = forkset[forkid] & OWNER_BIT;
95 if (currentowner == OWNER_SOURCE) {
98 if (philosopherset[source].state != EATING &&
99 (forkset[forkid] & DIRTY_BIT) &&
100 (forkset[forkid] & REQUEST_1)) {
103 forkset[forkid] = OWNER_TARGET;
104 if (philosopherset[source].state == HUNGRY) {
105 forkset[forkid] |= REQUEST_0;
107 philosopherset[source].forks_acquired--;
108 philosopherset[target].forks_acquired++;
114 if (philosopherset[target].state != EATING &&
115 (forkset[forkid] & DIRTY_BIT) &&
116 (forkset[forkid] & REQUEST_0)) {
119 forkset[forkid] = OWNER_SOURCE;
120 if (philosopherset[target].state == HUNGRY) {
121 forkset[forkid] |= REQUEST_1;
123 philosopherset[source].forks_acquired++;
124 philosopherset[target].forks_acquired--;
130 inline bool advance_fork_state_on_unlock(
size_t forkid,
134 unsigned char currentowner = forkset[forkid] & OWNER_BIT;
135 if (currentowner == OWNER_SOURCE) {
138 if ((forkset[forkid] & DIRTY_BIT) &&
139 (forkset[forkid] & REQUEST_1)) {
142 forkset[forkid] = OWNER_TARGET;
143 philosopherset[source].forks_acquired--;
144 philosopherset[target].forks_acquired++;
151 if ((forkset[forkid] & DIRTY_BIT) &&
152 (forkset[forkid] & REQUEST_0)) {
155 forkset[forkid] = OWNER_SOURCE;
156 philosopherset[source].forks_acquired++;
157 philosopherset[target].forks_acquired--;
164 void compute_initial_fork_arrangement() {
166 philosopherset[i].num_edges = graph.num_in_edges(i) +
167 graph.num_out_edges(i);
168 philosopherset[i].state = THINKING;
169 philosopherset[i].forks_acquired = 0;
172 foreach(
typename GraphType::edge_type edge, graph.in_edges(i)) {
173 if (edge.source() > edge.target()) {
174 forkset[graph.edge_id(edge)] = DIRTY_BIT | OWNER_TARGET;
175 philosopherset[edge.target()].forks_acquired++;
178 forkset[graph.edge_id(edge)] = DIRTY_BIT | OWNER_SOURCE;
179 philosopherset[edge.source()].forks_acquired++;
185 void compute_initial_fork_arrangement(
const std::vector<vertex_id_type> &altvids) {
187 philosopherset[i].num_edges = graph.num_in_edges(i) +
188 graph.num_out_edges(i);
189 philosopherset[i].state = THINKING;
190 philosopherset[i].forks_acquired = 0;
193 foreach(
typename GraphType::edge_type edge, graph.in_edges(i)) {
194 if (altvids[edge.source()] > altvids[edge.target()]) {
195 forkset[graph.edge_id(edge)] = DIRTY_BIT | OWNER_TARGET;
196 philosopherset[edge.target()].forks_acquired++;
199 forkset[graph.edge_id(edge)] = DIRTY_BIT | OWNER_SOURCE;
200 philosopherset[edge.source()].forks_acquired++;
214 philosopherset[v2].lock.lock();
216 else if (!philosopherset[v2].lock.try_lock()) {
217 philosopherset[v1].lock.unlock();
218 philosopherset[v2].lock.lock();
219 philosopherset[v1].lock.lock();
225 inline chandy_misra(GraphType &graph):graph(graph) {
226 forkset.resize(graph.num_edges(), 0);
227 philosopherset.resize(graph.num_vertices());
228 compute_initial_fork_arrangement();
231 inline chandy_misra(GraphType &graph,
232 const std::vector<vertex_id_type> &altvids):graph(graph) {
233 forkset.resize(graph.num_edges(), 0);
234 philosopherset.resize(graph.num_vertices());
235 compute_initial_fork_arrangement(altvids);
244 philosopherset[p_id].lock.lock();
246 ASSERT_EQ((
int)philosopherset[p_id].state, (
int)THINKING);
247 philosopherset[p_id].state = HUNGRY;
253 foreach(
typename GraphType::edge_type edge, graph.in_edges(p_id)) {
254 try_acquire_edge_with_backoff(edge.target(), edge.source());
256 size_t edgeid = graph.edge_id(edge);
258 if (fork_owner(edgeid) == OWNER_SOURCE) {
259 request_for_fork(edgeid, OWNER_TARGET);
260 advance_fork_state_on_lock(edgeid, edge.source(), edge.target());
262 philosopherset[edge.source()].lock.unlock();
265 foreach(
typename GraphType::edge_type edge, graph.out_edges(p_id)) {
267 try_acquire_edge_with_backoff(edge.source(), edge.target());
268 size_t edgeid = graph.edge_id(edge);
271 if (fork_owner(edgeid) == OWNER_TARGET) {
272 request_for_fork(edgeid, OWNER_SOURCE);
273 advance_fork_state_on_lock(edgeid, edge.source(), edge.target());
275 philosopherset[edge.target()].lock.unlock();
279 if (philosopherset[p_id].forks_acquired ==
280 philosopherset[p_id].num_edges) {
281 philosopherset[p_id].state = EATING;
285 philosopherset[p_id].lock.unlock();
289 inline std::vector<vertex_id_type> philosopher_stops_eating(
size_t p_id) {
290 std::vector<vertex_id_type> retval;
291 philosopherset[p_id].lock.lock();
293 ASSERT_EQ((
int)philosopherset[p_id].state, (
int)EATING);
294 philosopherset[p_id].state = THINKING;
297 foreach(
typename GraphType::edge_type edge, graph.in_edges(p_id)) {
298 try_acquire_edge_with_backoff(edge.target(), edge.source());
299 size_t edgeid = graph.edge_id(edge);
302 advance_fork_state_on_unlock(edgeid, edge.source(), edge.target());
303 if (philosopherset[other].state == HUNGRY &&
304 philosopherset[other].forks_acquired ==
305 philosopherset[other].num_edges) {
306 philosopherset[other].state = EATING;
308 retval.push_back(other);
310 philosopherset[other].lock.unlock();
313 foreach(
typename GraphType::edge_type edge, graph.out_edges(p_id)) {
314 try_acquire_edge_with_backoff(edge.source(), edge.target());
315 size_t edgeid = graph.edge_id(edge);
318 advance_fork_state_on_unlock(edgeid, edge.source(), edge.target());
319 if (philosopherset[other].state == HUNGRY &&
320 philosopherset[other].forks_acquired ==
321 philosopherset[other].num_edges) {
322 philosopherset[other].state = EATING;
324 retval.push_back(other);
326 philosopherset[other].lock.unlock();
329 philosopherset[p_id].lock.unlock();
333 inline std::vector<vertex_id_type> cancel_eating_philosopher(
vertex_id_type p_id) {
334 std::vector<vertex_id_type> retval;
335 philosopherset[p_id].lock.lock();
337 if(philosopherset[p_id].state != EATING) {
338 philosopherset[p_id].lock.unlock();
341 philosopherset[p_id].state = HUNGRY;
344 foreach(
typename GraphType::edge_type edge, graph.in_edges(p_id)) {
345 try_acquire_edge_with_backoff(edge.target(), edge.source());
346 size_t edgeid = graph.edge_id(edge);
348 if (fork_dirty(edgeid)) {
349 advance_fork_state_on_unlock(edgeid, edge.source(), edge.target());
350 if (philosopherset[other].state == HUNGRY &&
351 philosopherset[other].forks_acquired ==
352 philosopherset[other].num_edges) {
353 philosopherset[other].state = EATING;
355 retval.push_back(other);
358 philosopherset[other].lock.unlock();
361 foreach(
typename GraphType::edge_type edge, graph.out_edges(p_id)) {
362 try_acquire_edge_with_backoff(edge.source(), edge.target());
363 size_t edgeid = graph.edge_id(edge);
365 if (fork_dirty(edgeid)) {
366 advance_fork_state_on_unlock(edgeid, edge.source(), edge.target());
367 if (philosopherset[other].state == HUNGRY &&
368 philosopherset[other].forks_acquired ==
369 philosopherset[other].num_edges) {
370 philosopherset[other].state = EATING;
372 retval.push_back(other);
375 philosopherset[other].lock.unlock();
378 if (philosopherset[p_id].forks_acquired ==
379 philosopherset[p_id].num_edges) {
380 philosopherset[p_id].state = EATING;
382 retval.push_back(p_id);
384 philosopherset[p_id].lock.unlock();
389 void no_locks_consistency_check() {
391 for (
size_t i = 0;i < forkset.size(); ++i) ASSERT_TRUE(fork_dirty(i));
393 for (
size_t i = 0;i < philosopherset.size(); ++i) ASSERT_TRUE(philosopherset[i].state == THINKING);
396 void complete_consistency_check() {
400 size_t numowned_clean = 0;
401 foreach(
typename GraphType::edge_type edge, graph.in_edges(v)) {
402 size_t edgeid = graph.edge_id(edge);
403 if (fork_owner(edgeid) == OWNER_TARGET) {
405 if (!fork_dirty(edgeid)) numowned_clean++;
408 foreach(
typename GraphType::edge_type edge, graph.out_edges(v)) {
409 size_t edgeid = graph.edge_id(edge);
410 if (fork_owner(edgeid) == OWNER_SOURCE) {
412 if (!fork_dirty(edgeid)) numowned_clean++;
416 ASSERT_EQ(philosopherset[v].forks_acquired, numowned);
417 if (philosopherset[v].state == THINKING) {
418 ASSERT_EQ(numowned_clean, 0);
420 else if (philosopherset[v].state == HUNGRY) {
421 ASSERT_NE(philosopherset[v].num_edges, philosopherset[v].forks_acquired);
424 foreach(
typename GraphType::edge_type edge, graph.in_edges(v)) {
425 size_t edgeid = graph.edge_id(edge);
427 if (fork_owner(edgeid) == OWNER_SOURCE) {
428 if (philosopherset[edge.source()].state != EATING) {
429 if (fork_dirty(edgeid)) {
430 std::cout << (int)(forkset[edgeid]) <<
" "
431 << (int)philosopherset[edge.source()].state
432 <<
"->" << (int)philosopherset[edge.target()].state
434 ASSERT_FALSE(fork_dirty(edgeid));
437 ASSERT_NE(philosopherset[edge.source()].state, (int)THINKING);
440 foreach(
typename GraphType::edge_type edge, graph.out_edges(v)) {
441 size_t edgeid = graph.edge_id(edge);
442 if (fork_owner(edgeid) == OWNER_TARGET) {
443 if (philosopherset[edge.target()].state != EATING) {
444 if (fork_dirty(edgeid)) {
445 std::cout << (int)(forkset[edgeid]) <<
" "
446 << (int)philosopherset[edge.source()].state
448 << (int)philosopherset[edge.target()].state
450 ASSERT_FALSE(fork_dirty(edgeid));
453 ASSERT_NE(philosopherset[edge.target()].state, (int)THINKING);
458 else if (philosopherset[v].state == EATING) {
459 ASSERT_EQ(philosopherset[v].forks_acquired, philosopherset[v].num_edges);
467 #include <graphlab/macros_undef.hpp>