diff --git a/arangod/Cluster/v8-cluster.cpp b/arangod/Cluster/v8-cluster.cpp index 8d3e40e59e..3e9de11b8e 100644 --- a/arangod/Cluster/v8-cluster.cpp +++ b/arangod/Cluster/v8-cluster.cpp @@ -1348,6 +1348,7 @@ static void JS_EnableSyncReplicationDebug( } ServerState::instance()->setInitialized(); + ServerState::instance()->setId("repltest"); AgencyComm::syncReplDebug = true; TRI_V8_TRY_CATCH_END } diff --git a/js/server/modules/@arangodb/cluster.js b/js/server/modules/@arangodb/cluster.js index c616d1707b..24891e9d02 100644 --- a/js/server/modules/@arangodb/cluster.js +++ b/js/server/modules/@arangodb/cluster.js @@ -1197,25 +1197,28 @@ function executePlanForDatabases(plannedDatabases) { // / @brief updateCurrentForDatabases // ///////////////////////////////////////////////////////////////////////////// -function updateCurrentForDatabases(localErrors, current) { +function updateCurrentForDatabases(localErrors, currentDatabases) { let ourselves = global.ArangoServerState.id(); - function makeAddDatabaseAgencyOperation(payload, trx) { - trx[0][curDatabases + payload.name + '/' + ourselves] = + function makeAddDatabaseAgencyOperation(payload) { + let create = {}; + create[curDatabases + payload.name + '/' + ourselves] = {op: 'set', new: payload}; + return create; }; - function makeDropDatabaseAgencyOperation(name, trx) { - trx[0][curDatabases + name + '/' + ourselves] = {'op':'delete'}; + function makeDropDatabaseAgencyOperation(name) { + let drop = {}; + drop[curDatabases + name + '/' + ourselves] = {'op':'delete'}; + return drop; }; let db = require('internal').db; db._useDatabase('_system'); let localDatabases = getLocalDatabases(); - let currentDatabases = current.Databases; let name; - let trx = [{}]; // Here we collect all write operations + let trx = {}; // Here we collect all write operations // Add entries that we have but that are not in Current: for (name in localDatabases) { @@ -1223,13 +1226,13 @@ function updateCurrentForDatabases(localErrors, current) { if (!currentDatabases.hasOwnProperty(name) || !currentDatabases[name].hasOwnProperty(ourselves)) { console.debug("adding entry in Current for database '%s'", name); - makeAddDatabaseAgencyOperation({error: false, errorNum: 0, name: name, + trx = Object.assign(trx, makeAddDatabaseAgencyOperation({error: false, errorNum: 0, name: name, id: localDatabases[name].id, - errorMessage: ""}, trx); + errorMessage: ""})); } } } - + // Remove entries from current that no longer exist locally: for (name in currentDatabases) { if (currentDatabases.hasOwnProperty(name) && name.substr(0, 1) !== '_') { @@ -1239,7 +1242,7 @@ function updateCurrentForDatabases(localErrors, current) { if (currentDatabases[name].hasOwnProperty(ourselves)) { // we are entered for a database that we don't have locally console.debug("cleaning up entry for unknown database '%s'", name); - makeDropDatabaseAgencyOperation(name, trx); + trx = Object.assign(trx, makeDropDatabaseAgencyOperation(name)); } } } @@ -1247,12 +1250,10 @@ function updateCurrentForDatabases(localErrors, current) { // Finally, report any errors that might have been produced earlier when // we were trying to execute the Plan: - for (name in localErrors) { - if (localErrors.hasOwnProperty(name)) { - console.debug("reporting error to Current about database '%s'", name); - makeAddDatabaseAgencyOperation(localErrors[name], trx); - } - } + Object.keys(localErrors).forEach(name => { + console.debug("reporting error to Current about database '%s'", name); + trx = Object.assign(trx, makeAddDatabaseAgencyOperation(localErrors[name])); + }); return trx; } @@ -1268,7 +1269,8 @@ function migrateAnyServer(plan, current) { // diff current and local and prepare agency transactions or whatever // to update current. will report the errors created locally to the agency let trx = updateCurrentForDatabases(localErrors, current); - if (Object.keys(trx[0]).length !== 0) { + if (Object.keys(trx).length !== 0) { + trx = [trx]; trx[0][curVersion] = {op: 'increment'}; // TODO: reduce timeout when we can: try { @@ -1939,3 +1941,5 @@ exports.waitForSyncRepl = waitForSyncRepl; exports.executePlanForDatabases = executePlanForDatabases; exports.executePlanForCollections = executePlanForCollections; +exports.updateCurrentForDatabases = updateCurrentForDatabases; +exports.updateCurrentForCollections = updateCurrentForCollections; diff --git a/js/server/tests/cluster-sync/cluster-sync-test-noncluster-spec.js b/js/server/tests/cluster-sync/cluster-sync-test-noncluster-spec.js index 4cce429a98..c1986ed938 100644 --- a/js/server/tests/cluster-sync/cluster-sync-test-noncluster-spec.js +++ b/js/server/tests/cluster-sync/cluster-sync-test-noncluster-spec.js @@ -32,11 +32,11 @@ const expect = require('chai').expect; const ArangoCollection = require('@arangodb/arango-collection').ArangoCollection; describe('Cluster sync', function() { - describe('Databaseplan to local', function() { - before(function() { - require('@arangodb/sync-replication-debug').setup(); - }); + before(function() { + require('@arangodb/sync-replication-debug').setup(); + }); + describe('Databaseplan to local', function() { beforeEach(function() { db._databases().forEach(database => { if (database !== '_system') { @@ -141,7 +141,7 @@ describe('Cluster sync', function() { ], "shards": { "s100001": [ - "", + "repltest", ] }, "status": 3, @@ -192,7 +192,7 @@ describe('Cluster sync', function() { ], "shards": { "s100001": [ - "", + "repltest", ] }, "status": 2, @@ -244,7 +244,7 @@ describe('Cluster sync', function() { ], "shards": { "s100001": [ - "", + "repltest", ] }, "status": 2, @@ -419,7 +419,7 @@ describe('Cluster sync', function() { ], "shards": { "s100001": [ - "" + "repltest", ] }, "status": 2, @@ -481,7 +481,7 @@ describe('Cluster sync', function() { ], "shards": { "s100001": [ - "", + "repltest", ] }, "status": 2, @@ -531,7 +531,7 @@ describe('Cluster sync', function() { ], "shards": { "Möter": [ - "", + "repltest", ] }, "status": 2, @@ -579,7 +579,7 @@ describe('Cluster sync', function() { ], "shards": { "s100001": [ - "", + "repltest", ] }, "status": 3, @@ -627,7 +627,7 @@ describe('Cluster sync', function() { "shards": { "s100001": [ "the leader-leader", - "", + "repltest", ] }, "status": 2, @@ -674,7 +674,7 @@ describe('Cluster sync', function() { ], "shards": { "s100001": [ - "", + "repltest", ] }, "status": 2, @@ -724,7 +724,7 @@ describe('Cluster sync', function() { "shards": { "s100001": [ "old-leader", - "", + "repltest", ] }, "status": 2, @@ -734,7 +734,7 @@ describe('Cluster sync', function() { } }; let errors = cluster.executePlanForCollections(plan); - plan.test['100001'].shards['s100001'] = [""]; + plan.test['100001'].shards['s100001'] = ["repltest"]; cluster.executePlanForCollections(plan); db._useDatabase('test'); expect(db._collection('s100001').isLeader()).to.equal(true); @@ -749,9 +749,32 @@ describe('Cluster sync', function() { }); }); it('should report a new database', function() { - let Current = { - Databases: {}, + db._createDatabase('testi'); + let current = { + _system: { + repltest: { + id: 1, + name: '_system', + }, + } }; + let result = cluster.updateCurrentForDatabases({}, current); + expect(result).to.have.property('/arango/Current/Databases/testi/repltest'); + expect(result['/arango/Current/Databases/testi/repltest']).to.have.property('op', 'set'); + expect(result['/arango/Current/Databases/testi/repltest']).to.have.deep.property('new.name', 'testi'); + }); + it('should not do anything if there is nothing to do', function() { + let current = { + _system: { + repltest: { + id: 1, + name: '_system', + }, + } + }; + let result = cluster.updateCurrentForDatabases({}, current); + + expect(Object.keys(result)).to.have.lengthOf(0); }); }); });