Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Hazelcast v3.9 #19

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 6 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ In addition to our `com.noctarius.snowcast.Snowcast` factory, a custom epoch mus

```java
Calendar calendar = GregorianCalendar.getInstance();
calendar.set( 2014, Calendar.JANUARY, 1, 0, 0, 0 );
calendar.set( 2017, Calendar.JANUARY, 1, 0, 0, 0 );
SnowcastEpoch epoch = SnowcastEpoch.byCalendar( calendar );
```

Expand Down Expand Up @@ -151,62 +151,13 @@ Destroying a sequencer is a cluster operation and will destroy all sequencers re

### Hazelcast Configuration

snowcast 2.0 uses a custom service that is automatically registered with Hazelcast on startup. It supports Hazelcast 3.7.x and 3.8.x. To get started with snowcast simply provide the according JAR file in the classpath of the application. No additional step's necessary. For older snowcast versions see below.

For snowcast 1.0; Hazelcast requires custom services to be configured upfront using either the Configuration API or by utilizing the, XML based, declarative configuration.
snowcast uses a custom service that is automatically registered with Hazelcast on startup. Snowcast 2.0 supports Hazelcast 3.7.x and 3.8.x. snowcast 2.1 supports 3.9.x. To get started with snowcast simply provide the according JAR file in the classpath of the application. No additional step's necessary. For older snowcast versions see below.

snowcast offers three different ways to register the snowcast service with Hazelcast by providing support for the two already named ones and additionally is equipped with a hack to lazily registers itself as a Hazelcast service on first acquisition. This way is not meant to be used in production, the reason will be shown in a bit.

#### Using the Configuration API

As of snowcast 2.0 no manual configuration is required anymore. This chapter, however, stays for reference of snowcast 1.0.

The simplest way to configure snowcast is using the Hazelcast Configuration API. snowcast provides the user with a helper class to configure all necessary options.

If no other configuration is necessary let the snowcast helper create the `com.hazelcast.config.Config` instance for you, using the same way as Hazelcast itself would do it, and retrieve a pre-configured `Config` ready to be used to create a Hazelcast instance.

```java
Config config = SnowcastNodeConfigurator.buildSnowcastAwareConfig();
HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance( config );
```

If there is already a `Config` instance this can be passed in and configured to use snowcast.

```java
Config config = new Config();
config = SnowcastNodeConfigurator.buildSnowcastAwareConfig( config );
HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance( config );
```

#### Using the Declarative Configuration

As of snowcast 2.0 no manual configuration is required anymore. This chapter, however, stays for reference of snowcast 1.0.

For people configuring Hazelcast using the XML based configuration only, snowcast also supports a configuration based on declarative configuration. As a disadvantage using the declarative configuration the internal classname of the service is bound to the configuration. Whenever the classname might change for any reason instantiating Hazelcast might fail for an non-obvious reason. Using the [Configuration API](#using-the-configuration-api) is recommended.

```xml
<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.4.xsd"
xmlns="http://www.hazelcast.com/schema/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<services enable-defaults="true">
<service enabled="true">
<name>noctarius::SequencerService</name>
<class-name>com.noctarius.snowcast.impl.NodeSequencerService</class-name>
</service>
</services>
</hazelcast>
```

That way the snowcast service is registered into Hazelcast.

#### Lazy Configuration Hack (removed)

The previously available "Lazy Configuration Hack" has been removed from snowcast 1.0.0.

### Hazelcast Client Configuration

snowcast 2.0 snapshots currently support Hazelcast 3.7.x, 3.8.x. The underlying communication system is automatically registered.
snowcast 2.0 snapshots currently support Hazelcast 3.7.x, 3.8.x. snowcast 2.1 supports Hazelcast 3.9.x. The underlying communication system is automatically registered.

For older versions, snowcast 1.0 supports Hazelcast 3.4.x as well as Hazelcast 3.5.x and automatically registers a matching communication system.

Expand All @@ -229,7 +180,7 @@ snowcast is deployed as a Apache Maven artifact. All release candidates as well
<dependency>
<groupId>com.noctarius.snowcast</groupId>
<artifactId>snowcast</artifactId>
<version>1.0.0</version>
<version>2.1.0</version>
</dependency>
```

Expand All @@ -254,7 +205,7 @@ The Maven coordinates for the snowcast artifacts are:
<dependency>
<groupId>com.noctarius.snowcast</groupId>
<artifactId>snowcast</artifactId>
<version>2.0.0-SNAPSHOT</version>
<version>2.1.0-SNAPSHOT</version>
</dependency>
```

Expand Down Expand Up @@ -341,7 +292,7 @@ HazelcastInstance hazelcastClient = getHazelcastClient();
Snowcast snowcast = SnowcastSystem.snowcast( hazelcastClient );

Calendar calendar = GregorianCalendar.getInstance();
calendar.set( 2014, Calendar.JANUARY, 1, 0, 0, 0 );
calendar.set( 2017, Calendar.JANUARY, 1, 0, 0, 0 );
SnowcastEpoch epoch = SnowcastEpoch.byCalendar( calendar );

SnowcastSequencer sequencer = snowcast.createSequencer( "sequencerName", epoch );
Expand Down
12 changes: 6 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.noctarius.snowcast</groupId>
<artifactId>snowcast</artifactId>
<version>2.0.0-SNAPSHOT</version>
<version>2.1.0-SNAPSHOT</version>
<description>snowcast is an auto-configuration, distributed, scalable ID generator on top of Hazelcast</description>
<inceptionYear>2014</inceptionYear>
<url>http://github.com/noctarius/snowcast</url>
Expand Down Expand Up @@ -70,7 +70,7 @@
</ciManagement>

<properties>
<hazelcast.version>3.7.4</hazelcast.version>
<hazelcast.version>3.9</hazelcast.version>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
</properties>
Expand All @@ -90,13 +90,13 @@
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-client-protocol</artifactId>
<version>1.4.0-7</version>
<version>1.5.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-code-generator</artifactId>
<version>1.4.0-7</version>
<version>1.5.0</version>
<scope>provided</scope>
</dependency>

Expand Down Expand Up @@ -258,7 +258,7 @@
<excludePackageNames>*.impl.*</excludePackageNames>
<detectJavaApiLink>true</detectJavaApiLink>
<links>
<link>http://docs.hazelcast.org/docs/3.7/javadoc/</link>
<link>http://docs.hazelcast.org/docs/3.8/javadoc/</link>
</links>
</configuration>
</execution>
Expand Down Expand Up @@ -360,7 +360,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.1</version>
<version>1.4</version>
<executions>
<execution>
<id>sign-artifacts</id>
Expand Down
16 changes: 5 additions & 11 deletions src/main/java/com/noctarius/snowcast/SnowcastSystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,16 @@
package com.noctarius.snowcast;

import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.instance.HazelcastInstanceImpl;
import com.hazelcast.instance.HazelcastInstanceProxy;
import com.hazelcast.nio.ClassLoaderUtil;
import com.noctarius.snowcast.impl.ClientSnowcastFactory;
import com.noctarius.snowcast.impl.NodeSnowcastFactory;
import com.noctarius.snowcast.impl.SequencerService;

import java.util.Map;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.ThreadSafe;
import javax.validation.constraints.Max;
import java.lang.reflect.Method;
import java.util.Map;

import static com.noctarius.snowcast.impl.ExceptionMessages.BACKUP_COUNT_TOO_HIGH;
import static com.noctarius.snowcast.impl.ExceptionMessages.BACKUP_COUNT_TOO_LOW;
Expand Down Expand Up @@ -126,18 +125,13 @@ public static Snowcast snowcast(@Nonnull HazelcastInstance hazelcastInstance,
}

// Node setup
if (hazelcastInstance instanceof HazelcastInstanceProxy) {
if (hazelcastInstance instanceof HazelcastInstanceProxy || hazelcastInstance instanceof HazelcastInstanceImpl) {
snowcast = NodeSnowcastFactory.snowcast(hazelcastInstance, (short) backupCount);
}

// Client setup
if (snowcast == null) {
snowcast = execute(() -> {
String className = SequencerService.class.getPackage().getName() + ".ClientSnowcastFactory";
Class<?> clazz = ClassLoaderUtil.loadClass(null, className);
Method snowcastMethod = clazz.getMethod("snowcast", HazelcastInstance.class, short.class);
return (Snowcast) snowcastMethod.invoke(clazz, hazelcastInstance, (short) backupCount);
});
snowcast = execute(() -> ClientSnowcastFactory.snowcast(hazelcastInstance, (short) backupCount));
}

userContext.put(USER_CONTEXT_LOOKUP_NAME, snowcast);
Expand Down
17 changes: 7 additions & 10 deletions src/main/java/com/noctarius/snowcast/impl/ClientCodec.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,8 @@

import com.hazelcast.client.impl.HazelcastClientInstanceImpl;
import com.hazelcast.client.impl.protocol.ClientMessage;
import com.hazelcast.client.impl.protocol.codec.SnowcastAttachLogicalNodeCodec;
import com.hazelcast.client.impl.protocol.codec.SnowcastCreateSequencerDefinitionCodec;
import com.hazelcast.client.impl.protocol.codec.SnowcastDestroySequencerDefinitionCodec;
import com.hazelcast.client.impl.protocol.codec.SnowcastDetachLogicalNodeCodec;
import com.hazelcast.client.impl.protocol.codec.SnowcastRegisterChannelCodec;
import com.hazelcast.client.impl.protocol.codec.SnowcastRemoveChannelCodec;
import com.hazelcast.client.impl.protocol.codec.*;
import com.hazelcast.client.spi.impl.ClientInvocation;
import com.hazelcast.core.Partition;
import com.hazelcast.core.PartitionService;
import com.noctarius.snowcast.SnowcastEpoch;
Expand All @@ -32,11 +28,11 @@

final class ClientCodec {

private final ClientInvocator clientInvocator;
private final HazelcastClientInstanceImpl client;
private final PartitionService partitionService;

ClientCodec(HazelcastClientInstanceImpl client, ClientInvocator clientInvocator) {
this.clientInvocator = clientInvocator;
ClientCodec(HazelcastClientInstanceImpl client) {
this.client = client;
this.partitionService = client.getPartitionService();
}

Expand Down Expand Up @@ -106,7 +102,8 @@ private int partitionId(@Nonnull String sequencerName) {
private ClientMessage invoke(@Nonnull String sequencerName, @Nonnull ClientMessage request) {
return ExceptionUtils.execute(() -> {
int partitionId = partitionId(sequencerName);
return clientInvocator.invoke(partitionId, request).get();
ClientInvocation clientInvocation = new ClientInvocation(client, request, "snowcast", partitionId);
return clientInvocation.invoke().get();
});
}

Expand Down
30 changes: 0 additions & 30 deletions src/main/java/com/noctarius/snowcast/impl/ClientInvocator.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ public class ClientSequencer
private final ClientSequencerService sequencerService;

ClientSequencer(@Nonnull ClientSequencerService sequencerService, @Nonnull SequencerDefinition definition,
@Nonnull ClientCodec clientCodec) {
@Nonnull ClientCodec clientCodec, @Nonnull ClientContext clientContext) {

super(SnowcastConstants.SERVICE_NAME, definition.getSequencerName());
super(SnowcastConstants.SERVICE_NAME, definition.getSequencerName(), clientContext);
this.sequencerService = sequencerService;
this.sequencerContext = new ClientSequencerContext(definition, clientCodec);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
*/
package com.noctarius.snowcast.impl;

import com.hazelcast.client.spi.ClientProxy;
import com.hazelcast.client.impl.HazelcastClientInstanceImpl;
import com.hazelcast.client.impl.protocol.ClientMessage;
import com.hazelcast.client.impl.protocol.codec.ClientCreateProxyCodec;
import com.hazelcast.client.spi.ProxyManager;
import com.hazelcast.client.spi.impl.ClientInvocation;
import com.hazelcast.nio.Address;
import com.hazelcast.util.ConstructorFunction;

import javax.annotation.Nonnull;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;

final class ClientSequencerConstructorFunction
implements ConstructorFunction<SequencerDefinition, SequencerProvision> {
Expand All @@ -33,42 +34,38 @@ final class ClientSequencerConstructorFunction
private final ClientCodec clientCodec;
private final ProxyManager proxyManager;
private final ClientSequencerService sequencerService;
private final MethodHandle proxyManagerInitialize;
private final HazelcastClientInstanceImpl client;

ClientSequencerConstructorFunction(@Nonnull ProxyManager proxyManager, @Nonnull ClientSequencerService sequencerService,
ClientSequencerConstructorFunction(@Nonnull HazelcastClientInstanceImpl client,
@Nonnull ProxyManager proxyManager,
@Nonnull ClientSequencerService sequencerService,
@Nonnull ClientCodec clientCodec) {

this.client = client;
this.clientCodec = clientCodec;
this.proxyManager = proxyManager;
this.sequencerService = sequencerService;
this.proxyManagerInitialize = getInitializeMethod();
}

@Nonnull
@Override
public SequencerProvision createNew(@Nonnull SequencerDefinition definition) {
TRACER.trace("create new provision for definition %s", definition);
ClientSequencer sequencer = new ClientSequencer(sequencerService, definition, clientCodec);
initializeProxy(sequencer);
ClientSequencer sequencer = new ClientSequencer(sequencerService, definition, clientCodec, proxyManager.getContext());

Address initializationTarget = proxyManager.findNextAddressToSendCreateRequest();
if (initializationTarget == null) {
throw new RuntimeException("Not able to find a member to create proxy on!");
} else {
ClientMessage clientMessage = ClientCreateProxyCodec.encodeRequest(
definition.getSequencerName(), sequencer.getServiceName(), initializationTarget);
ExceptionUtils.execute(() -> {
new ClientInvocation(client, clientMessage, sequencer.getServiceName(), initializationTarget)
.invoke().get();
return null;
});
sequencer.onInitialize();
}
sequencer.attachLogicalNode();
return new SequencerProvision(definition, sequencer);
}

private void initializeProxy(@Nonnull ClientSequencer sequencer) {
//ACCESSIBILITY_HACK
ExceptionUtils.execute(() -> {
TRACER.trace("initialize sequencer proxy %s", sequencer);
return proxyManagerInitialize.invoke(proxyManager, sequencer);
});
}

@Nonnull
private MethodHandle getInitializeMethod() {
return ExceptionUtils.execute(() -> {
MethodHandles.Lookup lookup = MethodHandles.lookup();
Method method = ProxyManager.class.getDeclaredMethod("initialize", ClientProxy.class);
method.setAccessible(true);
return lookup.unreflect(method);
});
}
}
Loading