From de45d207d84300bcd4d599c407ec9615ed573a3d Mon Sep 17 00:00:00 2001 From: Mark Needham Date: Tue, 24 Nov 2015 17:19:02 +0000 Subject: [PATCH] Updates to Neo4j server to introduce core-edge * Adds CORE and EDGE modes * Adds endpoints to the HTTP API to distinguish leader/follower --- .../enterprise/EnterpriseNeoServer.java | 66 ++++++++- ...seAvailabilityDiscoveryRepresentation.java | 45 ++++++ .../rest/CoreDatabaseAvailabilityService.java | 131 ++++++++++++++++++ ...java => DatabaseRoleInfoServerModule.java} | 6 +- 4 files changed, 240 insertions(+), 8 deletions(-) create mode 100644 enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/CoreDatabaseAvailabilityDiscoveryRepresentation.java create mode 100644 enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/CoreDatabaseAvailabilityService.java rename enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/{MasterInfoServerModule.java => DatabaseRoleInfoServerModule.java} (87%) diff --git a/enterprise/server-enterprise/src/main/java/org/neo4j/server/enterprise/EnterpriseNeoServer.java b/enterprise/server-enterprise/src/main/java/org/neo4j/server/enterprise/EnterpriseNeoServer.java index 26a35feaaab8..391c69563c47 100644 --- a/enterprise/server-enterprise/src/main/java/org/neo4j/server/enterprise/EnterpriseNeoServer.java +++ b/enterprise/server-enterprise/src/main/java/org/neo4j/server/enterprise/EnterpriseNeoServer.java @@ -25,6 +25,8 @@ import java.util.List; import java.util.regex.Pattern; +import org.neo4j.coreedge.server.core.CoreGraphDatabase; +import org.neo4j.coreedge.server.edge.EdgeGraphDatabase; import org.neo4j.graphdb.EnterpriseGraphDatabase; import org.neo4j.helpers.collection.Iterables; import org.neo4j.kernel.GraphDatabaseAPI; @@ -39,21 +41,43 @@ import org.neo4j.server.modules.ServerModule; import org.neo4j.server.rest.management.AdvertisableService; import org.neo4j.server.web.ServerInternalSettings; -import org.neo4j.server.webadmin.rest.MasterInfoServerModule; +import org.neo4j.server.webadmin.rest.DatabaseRoleInfoServerModule; import org.neo4j.server.webadmin.rest.MasterInfoService; import static java.util.Arrays.asList; + import static org.neo4j.helpers.collection.Iterables.mix; import static org.neo4j.server.database.LifecycleManagingDatabase.lifecycleManagingDatabase; public class EnterpriseNeoServer extends AdvancedNeoServer { - public static final String HA = "HA"; + public enum Mode + { + SINGLE, + HA, + CORE, + EDGE; + + public static Mode fromString( String value ) + { + try + { + return Mode.valueOf( value ); + } + catch ( IllegalArgumentException ex ) + { + return SINGLE; + } + } + + } + private static final GraphFactory HA_FACTORY = new GraphFactory() { @Override public GraphDatabaseAPI newGraphDatabase( Config config, Dependencies dependencies ) { + File storeDir = config.get( ServerInternalSettings.legacy_db_location ); return new HighlyAvailableGraphDatabase( storeDir, config.getParams(), dependencies ); } @@ -68,6 +92,26 @@ public GraphDatabaseAPI newGraphDatabase( Config config, Dependencies dependenci } }; + private static final GraphFactory CORE_FACTORY = new GraphFactory() + { + @Override + public GraphDatabaseAPI newGraphDatabase( Config config, Dependencies dependencies ) + { + File storeDir = config.get( ServerInternalSettings.legacy_db_location ); + return new CoreGraphDatabase( storeDir, config.getParams(), dependencies ); + } + }; + + private static final GraphFactory EDGE_FACTORY = new GraphFactory() + { + @Override + public GraphDatabaseAPI newGraphDatabase( Config config, Dependencies dependencies ) + { + File storeDir = config.get( ServerInternalSettings.legacy_db_location ); + return new EdgeGraphDatabase( storeDir, config.getParams(), dependencies ); + } + }; + public EnterpriseNeoServer( Config config, Dependencies dependencies, LogProvider logProvider ) { super( config, createDbFactory( config ), dependencies, logProvider ); @@ -75,16 +119,28 @@ public EnterpriseNeoServer( Config config, Dependencies dependencies, LogProvide protected static Database.Factory createDbFactory( Config config ) { - String mode = config.get( EnterpriseServerSettings.mode ).toUpperCase(); - return lifecycleManagingDatabase( mode.equals( HA ) ? HA_FACTORY : ENTERPRISE_FACTORY ); + final Mode mode = Mode.fromString( config.get( EnterpriseServerSettings.mode ).toUpperCase() ); + + switch ( mode ) + { + case HA: + return lifecycleManagingDatabase( HA_FACTORY ); + case CORE: + return lifecycleManagingDatabase( CORE_FACTORY ); + case EDGE: + return lifecycleManagingDatabase( EDGE_FACTORY ); + default: // Anything else gives community, including Mode.SINGLE + return lifecycleManagingDatabase( ENTERPRISE_FACTORY ); + } } + @SuppressWarnings( "unchecked" ) @Override protected Iterable createServerModules() { return mix( - asList( (ServerModule) new MasterInfoServerModule( webServer, getConfig(), + asList( (ServerModule) new DatabaseRoleInfoServerModule( webServer, getConfig(), logProvider ) ), super.createServerModules() ); } diff --git a/enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/CoreDatabaseAvailabilityDiscoveryRepresentation.java b/enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/CoreDatabaseAvailabilityDiscoveryRepresentation.java new file mode 100644 index 000000000000..351fa6c33cf0 --- /dev/null +++ b/enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/CoreDatabaseAvailabilityDiscoveryRepresentation.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2002-2015 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.server.webadmin.rest; + +import org.neo4j.server.rest.repr.MappingRepresentation; +import org.neo4j.server.rest.repr.MappingSerializer; + +public class CoreDatabaseAvailabilityDiscoveryRepresentation extends MappingRepresentation +{ + private static final String WRITABLE_KEY = "writable"; + private static final String DISCOVERY_REPRESENTATION_TYPE = "discovery"; + + private final String basePath; + private final String isWritableUri; + + public CoreDatabaseAvailabilityDiscoveryRepresentation( String basePath, String isWritableUri ) + { + super( DISCOVERY_REPRESENTATION_TYPE ); + this.basePath = basePath; + this.isWritableUri = isWritableUri; + } + + @Override + protected void serialize( MappingSerializer serializer ) + { + serializer.putUri( WRITABLE_KEY, basePath + isWritableUri ); + } +} diff --git a/enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/CoreDatabaseAvailabilityService.java b/enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/CoreDatabaseAvailabilityService.java new file mode 100644 index 000000000000..753facf10af7 --- /dev/null +++ b/enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/CoreDatabaseAvailabilityService.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2002-2015 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.server.webadmin.rest; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; + +import org.neo4j.coreedge.server.core.CoreGraphDatabase; +import org.neo4j.coreedge.raft.roles.Role; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.server.rest.management.AdvertisableService; +import org.neo4j.server.rest.repr.BadInputException; +import org.neo4j.server.rest.repr.OutputFormat; + +import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE; +import static javax.ws.rs.core.Response.Status.FORBIDDEN; +import static javax.ws.rs.core.Response.Status.NOT_FOUND; +import static javax.ws.rs.core.Response.Status.OK; +import static javax.ws.rs.core.Response.status; + +@Path(CoreDatabaseAvailabilityService.BASE_PATH) +public class CoreDatabaseAvailabilityService implements AdvertisableService +{ + public static final String BASE_PATH = "server/core"; + public static final String IS_WRITABLE_PATH = "/writable"; + public static final String IS_AVAILABLE_PATH = "/available"; + + private final OutputFormat output; + private final CoreGraphDatabase coreDatabase; + + public CoreDatabaseAvailabilityService( @Context OutputFormat output, @Context GraphDatabaseService db ) + { + this.output = output; + if ( db instanceof CoreGraphDatabase ) + { + this.coreDatabase = (CoreGraphDatabase) db; + } + else + { + this.coreDatabase = null; + } + } + + @GET + public Response discover() throws BadInputException + { + if ( coreDatabase == null ) + { + return status( FORBIDDEN ).build(); + } + + String isSlaveUri = IS_WRITABLE_PATH; + + return output.ok( new CoreDatabaseAvailabilityDiscoveryRepresentation( BASE_PATH, isSlaveUri ) ); + } + + @GET + @Path(IS_WRITABLE_PATH) + public Response isWritable() throws BadInputException + { + if ( coreDatabase == null ) + { + return status( FORBIDDEN ).build(); + } + + if ( coreDatabase.getRole() == Role.LEADER ) + { + return positiveResponse(); + } + + return negativeResponse(); + } + + @GET + @Path( IS_AVAILABLE_PATH ) + public Response isAvailable() + { + if ( coreDatabase == null ) + { + return status( FORBIDDEN ).build(); + } + + return positiveResponse(); + } + + private Response negativeResponse() + { + return plainTextResponse( NOT_FOUND, "false" ); + } + + private Response positiveResponse() + { + return plainTextResponse( OK, "true" ); + } + + private Response plainTextResponse( Response.Status status, String entityBody ) + { + return status( status ).type( TEXT_PLAIN_TYPE ).entity( entityBody ).build(); + } + + @Override + public String getName() + { + return "core"; + } + + @Override + public String getServerPath() + { + return BASE_PATH; + } +} diff --git a/enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/MasterInfoServerModule.java b/enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/DatabaseRoleInfoServerModule.java similarity index 87% rename from enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/MasterInfoServerModule.java rename to enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/DatabaseRoleInfoServerModule.java index fd94e20f9d62..c4ec44095ee1 100644 --- a/enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/MasterInfoServerModule.java +++ b/enterprise/server-enterprise/src/main/java/org/neo4j/server/webadmin/rest/DatabaseRoleInfoServerModule.java @@ -31,13 +31,13 @@ import static java.util.Arrays.asList; -public class MasterInfoServerModule implements ServerModule +public class DatabaseRoleInfoServerModule implements ServerModule { private final WebServer server; private final Config config; private final Log log; - public MasterInfoServerModule( WebServer server, Config config, LogProvider logProvider ) + public DatabaseRoleInfoServerModule( WebServer server, Config config, LogProvider logProvider ) { this.server = server; this.config = config; @@ -62,7 +62,7 @@ public void stop() private List getClassNames() { - return asList( MasterInfoService.class.getName() ); + return asList( MasterInfoService.class.getName(), CoreDatabaseAvailabilityService.class.getName() ); } private URI managementApiUri()