bool sync_recursive (sync_partner *sp, const char *path) { uint64_t ts = apteryx_timestamp (path); if (ts < sp->last_sync_local) { if (ts == 0) { /* Prune anything that is deleted */ apteryx_prune_sp (sp, path); } /* Skip anything that hasn't changed since last sync */ return true; } /* make sure the path doesn't end in '/' for the get */ char *get_path = strdup (path); if (get_path[strlen (get_path) - 1] == '/') { get_path[strlen (get_path) - 1] = '\0'; } /* now make sure the path ends in '/' for the search */ char *search_path = NULL; if (path[strlen (path) - 1] != '/') { if (asprintf (&search_path, "%s/", path) == -1) { ERROR ("SYNC couldn't allocate search path!\n"); search_path = NULL; free (get_path); return false; } } else { search_path = strdup (path); } /* Update this node */ char *value = apteryx_get (get_path); if (value) { /* only sync non-null values or you'll inadvertently prune */ apteryx_set_sp (sp, get_path, value); free (value); } free (get_path); /* Update all children */ GList *sync_paths = apteryx_search (search_path); free (search_path); for (GList *iter = sync_paths; iter; iter = iter->next) { sync_recursive (sp, iter->data); } g_list_free_full (sync_paths, free); // TODO: Update remote children that weren't already covered above // Specifically, look for local deletes that haven't propagated return true; }
uint64_t apteryx_get_timestamp_sp (sync_partner *sp, const char *path) { char *full_path = sp_path (sp, path); if (!full_path) { return false; } uint64_t res = apteryx_timestamp (full_path); free (full_path); return res; }
bool resync (sync_partner *sp) { uint64_t local_ts = apteryx_timestamp ("/"); if (local_ts > sp->last_sync_local) { /* go through the list of paths to sync to the partner */ pthread_rwlock_rdlock (&paths_lock); for (GList *iter = paths; iter; iter = iter->next) { DEBUG ("About to sync path %s to node %s\n", (char *)iter->data, sp->socket); sync_recursive (sp, iter->data); } pthread_rwlock_unlock (&paths_lock); } sp->last_sync_local = local_ts; sp->last_sync_remote = apteryx_get_timestamp_sp (sp, "/"); return true; }
/* Application entry point */ int main (int argc, char **argv) { const char *filter = NULL; APTERYX_MODE mode = -1; char *path = NULL; char *param = NULL; GList * _iter; int c; uint64_t value; /* Parse options */ while ((c = getopt (argc, argv, "hdsgftwpxlu::")) != -1) { switch (c) { case 'd': apteryx_debug = true; break; case 's': mode = MODE_SET; break; case 'g': mode = MODE_GET; break; case 'f': mode = MODE_FIND; break; case 't': mode = MODE_TRAVERSE; break; case 'w': mode = MODE_WATCH; break; case 'p': mode = MODE_PROVIDE; break; case 'x': mode = MODE_PROXY; break; case 'l': mode = MODE_TIMESTAMP; break; case 'u': mode = MODE_TEST; if (optarg && optarg[0] == '=') memmove(optarg, optarg+1, strlen(optarg)); filter = optarg; break; case '?': case 'h': default: usage (); return 0; } } for (c = optind; c < argc; c++) { if (path == NULL) path = argv[c]; else if (param == NULL) param = argv[c]; else { usage (); return 0; } } /* Handle SIGTERM/SIGINT/SIGPIPE gracefully */ if (mode != MODE_TEST) { signal (SIGTERM, (__sighandler_t) termination_handler); signal (SIGINT, (__sighandler_t) termination_handler); } switch (mode) { case MODE_GET: if (!path || param) { usage (); return 0; } apteryx_init (apteryx_debug); if ((param = apteryx_get (path))) { printf ("%s\n", param); free (param); } else printf ("Not found\n"); apteryx_shutdown (); break; case MODE_SET: if (!path) { usage (); return 0; } apteryx_init (apteryx_debug); if (!apteryx_set (path, param)) printf ("Failed\n"); apteryx_shutdown (); break; case MODE_FIND: if (!path || param) { usage (); return 0; } apteryx_init (apteryx_debug); GList *paths = apteryx_search (path); for (_iter = paths; _iter; _iter = _iter->next) printf (" %s\n", (char *) _iter->data); g_list_free_full (paths, free); apteryx_shutdown (); break; case MODE_TRAVERSE: if (param) { usage (); return 0; } if (!path) { path = ""; } apteryx_init (apteryx_debug); apteryx_dump (path, stdout); apteryx_shutdown (); break; case MODE_WATCH: if (param) { usage (); return 0; } if (!path) { path = "/"; } apteryx_init (apteryx_debug); apteryx_watch (path, watch_callback); while (running) pause (); apteryx_unwatch (path, watch_callback); apteryx_shutdown (); break; case MODE_PROVIDE: if (!path || !param) { usage (); return 0; } apteryx_init (apteryx_debug); provide_value = param; apteryx_provide (path, provide_callback); while (running) pause (); apteryx_unprovide (path, provide_callback); apteryx_shutdown (); break; case MODE_PROXY: if (!path || !param) { usage (); return 0; } apteryx_init (apteryx_debug); apteryx_proxy (path, param); apteryx_shutdown (); break; case MODE_TIMESTAMP: if (param) { usage (); return 0; } if (!path) { path = ""; } apteryx_init (apteryx_debug); value = apteryx_timestamp (path); printf ("%"PRIu64"\n", value); apteryx_shutdown (); break; case MODE_TEST: if (path || param) { usage (); return 0; } apteryx_init (apteryx_debug); run_unit_tests (filter); usleep (100000); apteryx_shutdown (); break; default: usage (); return 0; } return 0; }