From 79633a40a49cf3ef41491003982e75aa5149d975 Mon Sep 17 00:00:00 2001 From: Luca Garulli Date: Mon, 28 Oct 2024 20:33:11 -0400 Subject: [PATCH] Fixed issue on creating a replicated database (#1794) * fix: old even log file were not purged * fix: casting issue * chore: minor code optimization * fix: replication of database via HTTP command after servers are started --- .../com/arcadedb/database/JSONSerializer.java | 8 +- .../server/event/FileServerEventLog.java | 4 +- .../ha/message/InstallDatabaseRequest.java | 2 +- .../handler/PostServerCommandHandler.java | 2 +- ...TTP2ServersCreateReplicatedDatabaseIT.java | 95 +++++++++++++++++++ 5 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 server/src/test/java/com/arcadedb/server/ha/HTTP2ServersCreateReplicatedDatabaseIT.java diff --git a/engine/src/main/java/com/arcadedb/database/JSONSerializer.java b/engine/src/main/java/com/arcadedb/database/JSONSerializer.java index 98a0ad15ba..59e7a16912 100644 --- a/engine/src/main/java/com/arcadedb/database/JSONSerializer.java +++ b/engine/src/main/java/com/arcadedb/database/JSONSerializer.java @@ -43,11 +43,9 @@ public JSONObject map2json(final Map map, final DocumentType typ final JSONObject json = new JSONObject(); final Set includePropertiesSet; - if (includeProperties.length > 0) { - includePropertiesSet = new HashSet<>(); - for (String p : includeProperties) - includePropertiesSet.add(p); - } else + if (includeProperties.length > 0) + includePropertiesSet = new HashSet<>(Arrays.asList(includeProperties)); + else includePropertiesSet = null; for (final Map.Entry entry : map.entrySet()) { diff --git a/server/src/main/java/com/arcadedb/server/event/FileServerEventLog.java b/server/src/main/java/com/arcadedb/server/event/FileServerEventLog.java index 8583c4c5f3..4e2e03e67c 100644 --- a/server/src/main/java/com/arcadedb/server/event/FileServerEventLog.java +++ b/server/src/main/java/com/arcadedb/server/event/FileServerEventLog.java @@ -84,6 +84,7 @@ public void start() { // REMOVE THE OLDEST FILES while (existentFiles.size() > KEEP_FILES) { final String removed = existentFiles.remove(existentFiles.size() - 1); + FileUtils.deleteFile(new File(logDirectory, removed)); LogManager.instance().log(this, Level.FINE, "Deleted server event log file %s (keep max %d files)", removed, KEEP_FILES); } } @@ -92,7 +93,8 @@ public void start() { // ASSIGN THE NEXT NUMBER ++maxCounter; - newFileName = new File(logDirectory, FILE_PREFIX + new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date()) + "." + maxCounter + FILE_EXT); + newFileName = new File(logDirectory, + FILE_PREFIX + new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date()) + "." + maxCounter + FILE_EXT); try { if (!newFileName.createNewFile()) throw new ServerException("Error on creating new server event log file " + newFileName); diff --git a/server/src/main/java/com/arcadedb/server/ha/message/InstallDatabaseRequest.java b/server/src/main/java/com/arcadedb/server/ha/message/InstallDatabaseRequest.java index 75804c8c25..8a78c97425 100755 --- a/server/src/main/java/com/arcadedb/server/ha/message/InstallDatabaseRequest.java +++ b/server/src/main/java/com/arcadedb/server/ha/message/InstallDatabaseRequest.java @@ -39,7 +39,7 @@ public InstallDatabaseRequest(final String databaseName) { public HACommand execute(final HAServer server, final String remoteServerName, final long messageNumber) { try { server.getLeader().requestInstallDatabase(new Binary(), databaseName); - return null; + return new OkResponse(); } catch (IOException e) { throw new ReplicationException("Error on installing database '" + databaseName + "' on replica '" + server.getServerName() + "'", e); } diff --git a/server/src/main/java/com/arcadedb/server/http/handler/PostServerCommandHandler.java b/server/src/main/java/com/arcadedb/server/http/handler/PostServerCommandHandler.java index ed233b0cf0..877cf4f188 100644 --- a/server/src/main/java/com/arcadedb/server/http/handler/PostServerCommandHandler.java +++ b/server/src/main/java/com/arcadedb/server/http/handler/PostServerCommandHandler.java @@ -173,7 +173,7 @@ private void createDatabase(final String databaseName) { final ServerDatabase db = server.createDatabase(databaseName, ComponentFile.MODE.READ_WRITE); if (server.getConfiguration().getValueAsBoolean(GlobalConfiguration.HA_ENABLED)) { - final ReplicatedDatabase replicatedDatabase = (ReplicatedDatabase) db.getEmbedded(); + final ReplicatedDatabase replicatedDatabase = (ReplicatedDatabase) db.getWrappedDatabaseInstance(); replicatedDatabase.createInReplicas(); } } diff --git a/server/src/test/java/com/arcadedb/server/ha/HTTP2ServersCreateReplicatedDatabaseIT.java b/server/src/test/java/com/arcadedb/server/ha/HTTP2ServersCreateReplicatedDatabaseIT.java new file mode 100644 index 0000000000..635c6cc00a --- /dev/null +++ b/server/src/test/java/com/arcadedb/server/ha/HTTP2ServersCreateReplicatedDatabaseIT.java @@ -0,0 +1,95 @@ +/* + * Copyright © 2021-present Arcade Data Ltd (info@arcadedata.com) + * + * 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. + * + * SPDX-FileCopyrightText: 2021-present Arcade Data Ltd (info@arcadedata.com) + * SPDX-License-Identifier: Apache-2.0 + */ +package com.arcadedb.server.ha; + +import com.arcadedb.log.LogManager; +import com.arcadedb.serializer.json.JSONObject; +import com.arcadedb.server.BaseGraphServerTest; +import org.junit.jupiter.api.Test; + +import java.net.*; +import java.util.*; +import java.util.logging.*; + +import static org.assertj.core.api.Assertions.assertThat; + +public class HTTP2ServersCreateReplicatedDatabaseIT extends BaseGraphServerTest { + @Override + protected int getServerCount() { + return 2; + } + + @Override + protected boolean isCreateDatabases() { + return false; + } + + @Test + public void testCreateReplicatedDatabase() throws Exception { + final HttpURLConnection connection = (HttpURLConnection) new URL( + "http://127.0.0.1:248" + 0 + "/api/v1/server").openConnection(); + + // CREATE DATABASE ON THE LEADER + connection.setRequestMethod("POST"); + connection.setRequestProperty("Authorization", + "Basic " + Base64.getEncoder().encodeToString(("root:" + BaseGraphServerTest.DEFAULT_PASSWORD_FOR_TESTS).getBytes())); + try { + formatPayload(connection, new JSONObject().put("command", "create database " + getDatabaseName())); + connection.connect(); + final String response = readResponse(connection); + LogManager.instance().log(this, Level.FINE, "Response: ", null, response); + assertThat(connection.getResponseCode()).isEqualTo(200); + assertThat(connection.getResponseMessage()).isEqualTo("OK"); + } finally { + connection.disconnect(); + } + + // CREATE THE SCHEMA ON BOTH SERVER, ONE TYPE PER SERVER + testEachServer((serverIndex) -> { + final String response = command(serverIndex, "create vertex type VertexType" + serverIndex); + assertThat(response).contains("VertexType" + serverIndex) + .withFailMessage("Type " + (("VertexType" + serverIndex) + " not found on server " + serverIndex)); + }); + + Thread.sleep(300); + + // CHECK THE SCHEMA HAS BEEN PROPAGATED + testEachServer((serverIndex) -> command(serverIndex, "select from VertexType" + serverIndex)); + + // CREATE SOME VERTICES ON BOTH SERVERS + testEachServer((serverIndex) -> { + for (int i = 0; i < 100; i++) { + final String v1 = new JSONObject( + command(serverIndex, "create vertex VertexType" + serverIndex + + " content {\"name\":\"Jay\",\"surname\":\"Miner\",\"age\":69}")).getJSONArray( + "result").getJSONObject(0).getString("@rid"); + + testEachServer((checkServer) -> { + try { + assertThat(new JSONObject(command(checkServer, "select from " + v1)).getJSONArray("result")).isNotEmpty(). + withFailMessage("executed on server " + serverIndex + " checking on server " + serverIndex); + } catch (final Exception e) { + LogManager.instance().log(this, Level.SEVERE, "Error on checking for V1 on server " + checkServer); + throw e; + } + }); + } + }); + } +}