Skip to content

Commit

Permalink
Updates to Neo4j server to introduce core-edge
Browse files Browse the repository at this point in the history
* Adds CORE and EDGE modes
* Adds endpoints to the HTTP API to distinguish
  leader/follower
  • Loading branch information
Mark Needham committed Nov 25, 2015
1 parent 7441a60 commit de45d20
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 8 deletions.
Expand Up @@ -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;
Expand All @@ -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 );
}
Expand All @@ -68,23 +92,55 @@ 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 );
}

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<ServerModule> createServerModules()
{
return mix(
asList( (ServerModule) new MasterInfoServerModule( webServer, getConfig(),
asList( (ServerModule) new DatabaseRoleInfoServerModule( webServer, getConfig(),
logProvider ) ), super.createServerModules() );
}

Expand Down
@@ -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 <http://www.gnu.org/licenses/>.
*/
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 );
}
}
@@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}
Expand Up @@ -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;
Expand All @@ -62,7 +62,7 @@ public void stop()

private List<String> getClassNames()
{
return asList( MasterInfoService.class.getName() );
return asList( MasterInfoService.class.getName(), CoreDatabaseAvailabilityService.class.getName() );
}

private URI managementApiUri()
Expand Down

0 comments on commit de45d20

Please sign in to comment.