io.atomix.resource.Resource Maven / Gradle / Ivy
/*
* Copyright 2015 the original author or authors.
*
* 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
*/
package io.atomix.resource;
import io.atomix.catalyst.concurrent.Listener;
import io.atomix.catalyst.concurrent.ThreadContext;
import io.atomix.catalyst.serializer.Serializer;
import io.atomix.catalyst.util.Managed;
import io.atomix.copycat.Command;
import io.atomix.copycat.Query;
import io.atomix.copycat.session.Session;
import java.io.Serializable;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
/**
* Base class for fault-tolerant stateful distributed objects.
*
* Resources are stateful distributed objects that run across a set of {@link io.atomix.copycat.server.CopycatServer}s
* in a cluster.
*
* Resources can be created either as standalone {@link io.atomix.copycat.server.StateMachine}s in
* a typical Copycat cluster or as {@code Atomix} resources. Operations on the resource are translated into
* {@link Command}s and {@link Query}s which are submitted to the cluster where they're logged and
* replicated.
*
* Resource implementations must be annotated with the {@link ResourceTypeInfo} annotation to indicate the
* {@link ResourceStateMachine} to be used by the Atomix resource manager. Additionally, resources must be
* registered via the {@code ServiceLoader} pattern in a file at {@code META-INF/services/io.atomix.resource.Resource}
* on the class path. The resource registration allows the Atomix resource manager to locate and load the resource
* state machine on each server in the cluster.
*
* @param resource type
* @author Jordan Halterman
*/
public interface Resource> extends Managed {
/**
* Base class for cluster-wide resource configurations.
*
* Resource configurations control options specific to the resource's replicated {@link ResourceStateMachine}.
* These options might include a maximum collection size or the order of values in a multi-map.
*/
class Config extends Properties implements Serializable {
public Config() {
}
public Config(Properties defaults) {
super();
for (String property : defaults.stringPropertyNames()) {
setProperty(property, defaults.getProperty(property));
}
}
}
/**
* Base class for local resource options.
*
* Options are configurations that are specific to a local resource instance. The first time a resource
* is created by a client, the client may provide {@code Options} specifying the behavior of the resource
* instance. Those initial options configure the behavior of the resource instance on the local node only.
*/
class Options extends Properties {
public Options() {
}
public Options(Properties defaults) {
super(defaults);
}
}
/**
* Resource event type.
*
* An event type should be created for each distinct {@link Event} supported by a resource type.
* The event type provides an {@link #id()} that is used internally by Atomix to invoke event
* handlers within the resource client.
*/
interface EventType {
/**
* Returns the event type ID.
*
* The event type ID is used to identify event types when published from the server state
* machine to the client. Event type IDs must be unique within a resource type.
*
* @return The event type ID. This must be unique within a resource type.
*/
int id();
}
/**
* Resource event interface.
*
* Resources should implement this interface for event messages sent from {@link ResourceStateMachine}s
* to resource clients. Each event type should be associated with a unique {@link EventType} that indicates
* the event identifier.
*/
interface Event {
/**
* Returns the resource event type.
*
* The event type should be unique to the specific event as it's used as an event identifier.
*
* @return The resource event type.
*/
EventType type();
}
/**
* Resource session state constants.
*
* The resource state is indicative of the resource's ability to communicate with the cluster within the
* context of the underlying {@link Session}. In some cases, resource state changes may be indicative of a
* loss of guarantees. Users of the resource should {@link Resource#onStateChange(Consumer) watch} the state
* of a resource to determine when guarantees are lost and react to changes in the resource's ability to communicate
* with the cluster.
*
*
* {@code
* resource.onStateChange(state -> {
* switch (state) {
* case OPEN:
* // The resource is healthy
* break;
* case SUSPENDED:
* // The resource is unhealthy and operations may be unsafe
* break;
* case CLOSED:
* // The resource has been closed and pending operations have failed
* break;
* }
* });
* }
*
* So long as the resource is in the {@link #CONNECTED} state, all guarantees with respect to reads and writes will
* be maintained, and a loss of the {@code CONNECTED} state may indicate a loss of linearizability. See the specific
* states for more info.
*
* Reference resource documentation for implications of the various states on specific resources.
*/
enum State {
/**
* Indicates that the resource is connected and operating normally.
*
* The {@code CONNECTED} state indicates that the resource is healthy and operating normally. Operations submitted
* and completed while the resource is in this state are guaranteed to adhere to the configured consistency level.
*/
CONNECTED,
/**
* Indicates that the resource is suspended and its session may or may not be expired.
*
* The {@code SUSPENDED} state is indicative of an inability to communicate with the cluster within the context of
* the underlying client's {@link Session}. Operations performed on resources in this state should be considered
* unsafe. An operation performed on a {@link #CONNECTED} resource that transitions to the {@code SUSPENDED} state
* prior to the operation's completion may be committed multiple times in the event that the underlying session
* is ultimately {@link Session.State#EXPIRED expired}, thus breaking linearizability. Additionally, state machines
* may see the session expire while the resource is in this state.
*
* A resource that is in the {@code SUSPENDED} state may transition back to {@link #CONNECTED} once its underlying
* session is recovered. However, operations not yet completed prior to the resource's recovery may lose linearizability
* guarantees. If an operation is submitted while a resource is in the {@link #CONNECTED} state and the resource loses
* and recovers its session, the operation may be applied to the resource's state more than once. Operations completed
* across sessions are guaranteed to be performed at-least-once only.
*/
SUSPENDED,
/**
* Indicates that the resource is closed.
*
* A resource may transition to this state as a result of an expired session or an explicit {@link Resource#close() close}
* by the user or a closure of the resource's underlying client.
*/
CLOSED
}
/**
* Returns the resource type.
*
* @return The resource type.
*/
ResourceType type();
/**
* Returns the resource serializer.
*
* @return The resource serializer.
*/
Serializer serializer();
/**
* Returns the resource configuration.
*
* @return The resource configuration.
*/
Config config();
/**
* Returns the resource options.
*
* @return The configured resource options.
*/
Options options();
/**
* Returns the current resource state.
*
* The resource's {@link State} is indicative of the resource's ability to communicate with the cluster at any given
* time. Users of the resource should use the state to determine when guarantees may be lost. See the {@link State}
* documentation for information on the specific states, and see resource implementation documentation for the
* implications of different states on resource consistency.
*
* @return The current resource state.
*/
State state();
/**
* Registers a resource state change listener.
*
* @param callback The callback to call when the resource state changes.
* @return The state change listener.
*/
Listener onStateChange(Consumer callback);
/**
* Registers a listener which gets called after the resource recovery process
*
* @param callback The callback to call when the resource finishes recovery process.
* @return The recovery listener.
*/
Listener onRecovery(Consumer callback);
/**
* Returns the resource thread context.
*
* @return The resource thread context.
*/
ThreadContext context();
/**
* Opens the resource.
*
* Once the resource is opened, the resource will be transitioned to the {@link State#CONNECTED} state
* and the returned {@link CompletableFuture} will be completed.
*
* @return A completable future to be completed once the resource is opened.
*/
@Override
@SuppressWarnings("unchecked")
CompletableFuture open();
/**
* Closes the resource.
*
* Once the resource is closed, the resource will be transitioned to the {@link State#CLOSED} state and
* the returned {@link CompletableFuture} will be completed. Thereafter, attempts to operate on the resource
* will fail.
*
* @return A completable future to be completed once the resource is closed.
*/
@Override
CompletableFuture close();
/**
* Deletes the resource state.
*
* @return A completable future to be completed once the resource has been deleted.
*/
CompletableFuture delete();
}