'use strict'; //////////////////////////////////////////////////////////////////////////////// /// @brief Replication management /// /// @file /// /// DISCLAIMER /// /// Copyright 2012 triagens GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Jan Steemann /// @author Copyright 2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// var internal = require("internal"); var arangosh = require("@arangodb/arangosh"); var logger = {}; var applier = {}; //////////////////////////////////////////////////////////////////////////////// /// @brief return the replication logger state //////////////////////////////////////////////////////////////////////////////// logger.state = function() { var db = internal.db; var requestResult = db._connection.GET("/_api/replication/logger-state"); arangosh.checkRequestResult(requestResult); return requestResult; }; //////////////////////////////////////////////////////////////////////////////// /// @brief return the tick ranges that can be provided by the replication logger //////////////////////////////////////////////////////////////////////////////// logger.tickRanges = function() { var db = internal.db; var requestResult = db._connection.GET("/_api/replication/logger-tick-ranges"); arangosh.checkRequestResult(requestResult); return requestResult; }; //////////////////////////////////////////////////////////////////////////////// /// @brief return the first tick that can be provided by the replication logger //////////////////////////////////////////////////////////////////////////////// logger.firstTick = function() { var db = internal.db; var requestResult = db._connection.GET("/_api/replication/logger-first-tick"); arangosh.checkRequestResult(requestResult); return requestResult.firstTick; }; //////////////////////////////////////////////////////////////////////////////// /// @brief starts the replication applier //////////////////////////////////////////////////////////////////////////////// applier.start = function(initialTick) { var db = internal.db; var append = ""; if (initialTick !== undefined) { append = "?from=" + encodeURIComponent(initialTick); } var requestResult = db._connection.PUT("/_api/replication/applier-start" + append, ""); arangosh.checkRequestResult(requestResult); return requestResult; }; //////////////////////////////////////////////////////////////////////////////// /// @brief stops the replication applier //////////////////////////////////////////////////////////////////////////////// applier.stop = applier.shutdown = function() { var db = internal.db; var requestResult = db._connection.PUT("/_api/replication/applier-stop", ""); arangosh.checkRequestResult(requestResult); return requestResult; }; //////////////////////////////////////////////////////////////////////////////// /// @brief return the replication applier state //////////////////////////////////////////////////////////////////////////////// applier.state = function() { var db = internal.db; var requestResult = db._connection.GET("/_api/replication/applier-state"); arangosh.checkRequestResult(requestResult); return requestResult; }; //////////////////////////////////////////////////////////////////////////////// /// @brief stop the replication applier state and "forget" all state //////////////////////////////////////////////////////////////////////////////// applier.forget = function() { var db = internal.db; var requestResult = db._connection.DELETE("/_api/replication/applier-state"); arangosh.checkRequestResult(requestResult); return requestResult; }; //////////////////////////////////////////////////////////////////////////////// /// @brief configures the replication applier //////////////////////////////////////////////////////////////////////////////// applier.properties = function(config) { var db = internal.db; var requestResult; if (config === undefined) { requestResult = db._connection.GET("/_api/replication/applier-config"); } else { requestResult = db._connection.PUT("/_api/replication/applier-config", JSON.stringify(config)); } arangosh.checkRequestResult(requestResult); return requestResult; }; //////////////////////////////////////////////////////////////////////////////// /// @brief performs a one-time synchronization with a remote endpoint //////////////////////////////////////////////////////////////////////////////// var sync = function(config) { const db = internal.db; const body = JSON.stringify(config || {}); const headers = { "X-Arango-Async": "store" }; const requestResult = db._connection.PUT_RAW("/_api/replication/sync", body, headers); arangosh.checkRequestResult(requestResult); if (config.async) { return requestResult.headers["x-arango-async-id"]; } let count = 0; while (true) { const jobResult = db._connection.PUT( "/_api/job/" + requestResult.headers["x-arango-async-id"], ""); arangosh.checkRequestResult(jobResult); if (jobResult.code !== 204) { return jobResult; } if (++count % 6 === 0) { internal.print("still synchronizing, please wait..."); } internal.sleep(5); } }; //////////////////////////////////////////////////////////////////////////////// /// @brief performs a one-time synchronization with a remote endpoint, for /// a single collection //////////////////////////////////////////////////////////////////////////////// var syncCollection = function(collection, config) { var db = internal.db; config = config || {}; config.restrictType = "include"; config.restrictCollections = [collection]; config.includeSystem = true; return sync(config); }; //////////////////////////////////////////////////////////////////////////////// /// @brief sets up the replication (all-in-one function for initial /// synchronization and continuous replication) //////////////////////////////////////////////////////////////////////////////// var setupReplication = function(config) { config = config || { }; if (! config.hasOwnProperty('autoStart')) { config.autoStart = true; } if (! config.hasOwnProperty('includeSystem')) { config.includeSystem = true; } if (! config.hasOwnProperty('verbose')) { config.verbose = false; } const db = internal.db; const body = JSON.stringify(config); const headers = { "X-Arango-Async": "store" }; const requestResult = db._connection.PUT_RAW("/_api/replication/make-slave", body, headers); arangosh.checkRequestResult(requestResult); if (config.async) { return requestResult.headers["x-arango-async-id"]; } let count = 0; while (true) { const jobResult = db._connection.PUT( "/_api/job/" + requestResult.headers["x-arango-async-id"], ""); arangosh.checkRequestResult(jobResult); if (jobResult.code !== 204) { return jobResult; } if (++count % 6 === 0) { internal.print("still synchronizing, please wait..."); } internal.sleep(5); } }; //////////////////////////////////////////////////////////////////////////////// /// @brief queries the sync result status //////////////////////////////////////////////////////////////////////////////// var getSyncResult = function(id) { var db = internal.db; var requestResult = db._connection.PUT_RAW("/_api/job/" + encodeURIComponent(id), ""); arangosh.checkRequestResult(requestResult); if (requestResult.headers.hasOwnProperty("x-arango-async-id")) { return JSON.parse(requestResult.body); } return false; }; //////////////////////////////////////////////////////////////////////////////// /// @brief fetches a server's id //////////////////////////////////////////////////////////////////////////////// var serverId = function() { var db = internal.db; var requestResult = db._connection.GET("/_api/replication/server-id"); arangosh.checkRequestResult(requestResult); return requestResult.serverId; }; exports.logger = logger; exports.applier = applier; exports.sync = sync; exports.syncCollection = syncCollection; exports.setupReplication = setupReplication; exports.getSyncResult = getSyncResult; exports.serverId = serverId;