io.atomix.primitive.operation.PrimitiveOperation Java Examples

The following examples show how to use io.atomix.primitive.operation.PrimitiveOperation. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: RaftServiceContext.java    From atomix with Apache License 2.0 6 votes vote down vote up
/**
 * Ensures the given query is applied after the appropriate index.
 */
private void indexQuery(
    long index,
    long timestamp,
    RaftSession session,
    PrimitiveOperation operation,
    CompletableFuture<OperationResult> future) {
  // If the query index is greater than the session's last applied index, queue the request for handling once the
  // state machine is caught up.
  if (index > currentIndex) {
    log.trace("Registering query with index " + index + " > " + currentIndex);
    session.registerIndexQuery(index, () -> applyQuery(timestamp, session, operation, future));
  } else {
    applyQuery(timestamp, session, operation, future);
  }
}
 
Example #2
Source File: RaftServiceContext.java    From atomix with Apache License 2.0 6 votes vote down vote up
/**
 * Sequences the given query.
 */
private void sequenceQuery(
    long index,
    long sequence,
    long timestamp,
    RaftSession session,
    PrimitiveOperation operation,
    CompletableFuture<OperationResult> future) {
  // If the query's sequence number is greater than the session's current sequence number, queue the request for
  // handling once the state machine is caught up.
  long commandSequence = session.getCommandSequence();
  if (sequence > commandSequence) {
    log.trace("Registering query with sequence number " + sequence + " > " + commandSequence);
    session.registerSequenceQuery(sequence, () -> indexQuery(index, timestamp, session, operation, future));
  } else {
    indexQuery(index, timestamp, session, operation, future);
  }
}
 
Example #3
Source File: RaftServiceContext.java    From atomix with Apache License 2.0 6 votes vote down vote up
/**
 * Executes a query on the state machine thread.
 */
private void executeQuery(
    long index,
    long sequence,
    long timestamp,
    RaftSession session,
    PrimitiveOperation operation,
    CompletableFuture<OperationResult> future) {
  // If the service has been deleted then throw an unknown service exception.
  if (deleted) {
    log.warn("Service {} has been deleted by another process", serviceName);
    future.completeExceptionally(new RaftException.UnknownService("Service " + serviceName + " has been deleted"));
    return;
  }

  // If the session is not open, fail the request.
  if (!session.getState().active()) {
    log.warn("Inactive session: " + session.sessionId());
    future.completeExceptionally(new RaftException.UnknownSession("Unknown session: " + session.sessionId()));
    return;
  }

  // Otherwise, sequence the query.
  sequenceQuery(index, sequence, timestamp, session, operation, future);
}
 
Example #4
Source File: PrimaryBackupSessionClient.java    From atomix with Apache License 2.0 6 votes vote down vote up
@Override
public CompletableFuture<byte[]> execute(PrimitiveOperation operation) {
  ComposableFuture<byte[]> future = new ComposableFuture<>();
  threadContext.execute(() -> {
    if (term.primary() == null) {
      primaryElection.getTerm().whenCompleteAsync((term, error) -> {
        if (error == null) {
          if (term.term() <= this.term.term() || term.primary() == null) {
            future.completeExceptionally(new PrimitiveException.Unavailable());
          } else {
            this.term = term;
            execute(operation, 1, future);
          }
        } else {
          future.completeExceptionally(new PrimitiveException.Unavailable());
        }
      }, threadContext);
    } else {
      execute(operation, 1, future);
    }
  });
  return future;
}
 
Example #5
Source File: DefaultRaftSessionClient.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Override
public CompletableFuture<byte[]> execute(PrimitiveOperation operation) {
  RaftSessionInvoker invoker = this.proxyInvoker;
  if (invoker == null) {
    return Futures.exceptionalFuture(new IllegalStateException("Session not open"));
  }
  return invoker.invoke(operation);
}
 
Example #6
Source File: TestProtocolService.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Executes the given operation.
 *
 * @param sessionId the session performing the operation
 * @param operation the operation to execute
 * @return a future to be completed with the operation result
 */
public CompletableFuture<byte[]> execute(SessionId sessionId, PrimitiveOperation operation) {
  CompletableFuture<byte[]> future = new CompletableFuture<>();
  context.execute(() -> {
    Session session = sessions.get(sessionId);
    if (session == null) {
      future.completeExceptionally(new PrimitiveException.UnknownSession());
    }

    long timestamp = timestamp();
    this.session = session;
    this.operationType = operation.id().type();
    service.tick(new WallClockTimestamp(timestamp));

    try {
      byte[] result = service.apply(new DefaultCommit<>(
          index.incrementAndGet(),
          operation.id(),
          operation.value(),
          session,
          timestamp));
      future.complete(result);
    } catch (Exception e) {
      future.completeExceptionally(new PrimitiveException.ServiceException(e.getMessage()));
    }
  });
  return future;
}
 
Example #7
Source File: TestSessionClient.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Override
public CompletableFuture<byte[]> execute(PrimitiveOperation operation) {
  CompletableFuture<byte[]> future = new CompletableFuture<>();
  service.execute(sessionId, operation).whenCompleteAsync((result, error) -> {
    if (error == null) {
      future.complete(result);
    } else {
      future.completeExceptionally(error);
    }
  }, context);
  return future;
}
 
Example #8
Source File: RaftServiceManagerTest.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Test
public void testInstallSnapshotOnApply() throws Exception {
  RaftLogWriter writer = raft.getLogWriter();
  writer.append(new InitializeEntry(1, System.currentTimeMillis()));
  writer.append(new OpenSessionEntry(
      1,
      System.currentTimeMillis(),
      "test-1",
      "test",
      "test",
      null,
      ReadConsistency.LINEARIZABLE,
      100,
      1000));
  writer.commit(2);

  RaftServiceManager manager = raft.getServiceManager();

  manager.apply(2).join();

  Snapshot snapshot = manager.snapshot();
  assertEquals(2, snapshot.index());
  assertTrue(snapshotTaken.get());

  snapshot.complete();

  assertEquals(2, raft.getSnapshotStore().getCurrentSnapshot().index());

  writer.append(new CommandEntry(1, System.currentTimeMillis(), 2, 1, new PrimitiveOperation(RUN, new byte[0])));
  writer.commit(3);

  manager.apply(3).join();
  assertTrue(snapshotInstalled.get());
}
 
Example #9
Source File: RaftServiceContext.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Applies a query to the state machine.
 */
private void applyQuery(long timestamp, RaftSession session, PrimitiveOperation operation, CompletableFuture<OperationResult> future) {
  // If the service has been deleted then throw an unknown service exception.
  if (deleted) {
    log.warn("Service {} has been deleted by another process", serviceName);
    future.completeExceptionally(new RaftException.UnknownService("Service " + serviceName + " has been deleted"));
    return;
  }

  // If the session is not open, fail the request.
  if (!session.getState().active()) {
    log.warn("Inactive session: " + session.sessionId());
    future.completeExceptionally(new RaftException.UnknownSession("Unknown session: " + session.sessionId()));
    return;
  }

  // Set the current operation type to QUERY to prevent events from being sent to clients.
  setOperation(OperationType.QUERY);

  Commit<byte[]> commit = new DefaultCommit<>(currentIndex, operation.id(), operation.value(), session, timestamp);

  long eventIndex = session.getEventIndex();

  OperationResult result;
  try {
    currentSession = session;
    result = OperationResult.succeeded(currentIndex, eventIndex, service.apply(commit));
  } catch (Exception e) {
    result = OperationResult.failed(currentIndex, eventIndex, e);
  } finally {
    currentSession = null;
  }
  future.complete(result);
}
 
Example #10
Source File: RaftServiceContext.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Executes the given query on the state machine.
 *
 * @param index     The index of the query.
 * @param sequence  The query sequence number.
 * @param timestamp The timestamp of the query.
 * @param session   The session that submitted the query.
 * @param operation The query to execute.
 * @return A future to be completed with the query result.
 */
public CompletableFuture<OperationResult> executeQuery(
    long index,
    long sequence,
    long timestamp,
    RaftSession session,
    PrimitiveOperation operation) {
  CompletableFuture<OperationResult> future = new CompletableFuture<>();
  executeQuery(index, sequence, timestamp, session, operation, future);
  return future;
}
 
Example #11
Source File: RaftServiceContext.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Applies the given commit to the state machine.
 */
private OperationResult applyCommand(long index, long sequence, long timestamp, PrimitiveOperation operation, RaftSession session) {
  long eventIndex = session.getEventIndex();

  Commit<byte[]> commit = new DefaultCommit<>(index, operation.id(), operation.value(), session, timestamp);

  OperationResult result;
  try {
    currentSession = session;

    // Execute the state machine operation and get the result.
    byte[] output = service.apply(commit);

    // Store the result for linearizability and complete the command.
    result = OperationResult.succeeded(index, eventIndex, output);
  } catch (Exception e) {
    // If an exception occurs during execution of the command, store the exception.
    result = OperationResult.failed(index, eventIndex, e);
  } finally {
    currentSession = null;
  }

  // Once the operation has been applied to the state machine, commit events published by the command.
  // The state machine context will build a composite future for events published to all sessions.
  commit();

  // Register the result in the session to ensure retries receive the same output for the command.
  session.registerResult(sequence, result);

  // Update the session timestamp and command sequence number.
  session.setCommandSequence(sequence);

  // Complete the command.
  return result;
}
 
Example #12
Source File: RaftServiceContext.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Executes the given command on the state machine.
 *
 * @param index     The index of the command.
 * @param timestamp The timestamp of the command.
 * @param sequence  The command sequence number.
 * @param session   The session that submitted the command.
 * @param operation The command to execute.
 * @return A future to be completed with the command result.
 */
public OperationResult executeCommand(long index, long sequence, long timestamp, RaftSession session, PrimitiveOperation operation) {
  // If the service has been deleted then throw an unknown service exception.
  if (deleted) {
    log.warn("Service {} has been deleted by another process", serviceName);
    throw new RaftException.UnknownService("Service " + serviceName + " has been deleted");
  }

  // If the session is not open, fail the request.
  if (!session.getState().active()) {
    log.warn("Session not open: {}", session);
    throw new RaftException.UnknownSession("Unknown session: " + session.sessionId());
  }

  // Update the session's timestamp to prevent it from being expired.
  session.setLastUpdated(timestamp);

  // Update the state machine index/timestamp.
  tick(index, timestamp);

  // If the command's sequence number is less than the next session sequence number then that indicates that
  // we've received a command that was previously applied to the state machine. Ensure linearizability by
  // returning the cached response instead of applying it to the user defined state machine.
  if (sequence > 0 && sequence < session.nextCommandSequence()) {
    log.trace("Returning cached result for command with sequence number {} < {}", sequence, session.nextCommandSequence());
    return sequenceCommand(index, sequence, session);
  }
  // If we've made it this far, the command must have been applied in the proper order as sequenced by the
  // session. This should be the case for most commands applied to the state machine.
  else {
    // Execute the command in the state machine thread. Once complete, the CompletableFuture callback will be completed
    // in the state machine thread. Register the result in that thread and then complete the future in the caller's thread.
    return applyCommand(index, sequence, timestamp, operation, session);
  }
}
 
Example #13
Source File: RaftSessionInvoker.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Submits a query to the cluster.
 */
private void invokeQuery(PrimitiveOperation operation, CompletableFuture<byte[]> future) {
  QueryRequest request = QueryRequest.builder()
      .withSession(state.getSessionId().id())
      .withSequence(state.getCommandRequest())
      .withOperation(operation)
      .withIndex(Math.max(state.getResponseIndex(), state.getEventIndex()))
      .build();
  invokeQuery(request, future);
}
 
Example #14
Source File: RaftSessionInvoker.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Submits a command to the cluster.
 */
private void invokeCommand(PrimitiveOperation operation, CompletableFuture<byte[]> future) {
  CommandRequest request = CommandRequest.builder()
      .withSession(state.getSessionId().id())
      .withSequence(state.nextCommandRequest())
      .withOperation(operation)
      .build();
  invokeCommand(request, future);
}
 
Example #15
Source File: RaftSessionInvoker.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Submits a operation to the cluster.
 *
 * @param operation The operation to submit.
 * @return A completable future to be completed once the command has been submitted.
 */
public CompletableFuture<byte[]> invoke(PrimitiveOperation operation) {
  CompletableFuture<byte[]> future = new CompletableFuture<>();
  switch (operation.id().type()) {
    case COMMAND:
      context.execute(() -> invokeCommand(operation, future));
      break;
    case QUERY:
      context.execute(() -> invokeQuery(operation, future));
      break;
    default:
      throw new IllegalArgumentException("Unknown operation type " + operation.id().type());
  }
  return future;
}
 
Example #16
Source File: RetryingSessionClient.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Override
public CompletableFuture<byte[]> execute(PrimitiveOperation operation) {
  if (getState() == PrimitiveState.CLOSED) {
    return Futures.exceptionalFuture(new PrimitiveException.ClosedSession());
  }
  CompletableFuture<byte[]> future = new CompletableFuture<>();
  execute(operation, 1, future);
  return future;
}
 
Example #17
Source File: RetryingSessionClient.java    From atomix with Apache License 2.0 5 votes vote down vote up
private void execute(PrimitiveOperation operation, int attemptIndex, CompletableFuture<byte[]> future) {
  session.execute(operation).whenComplete((r, e) -> {
    if (e != null) {
      if (attemptIndex < maxRetries + 1 && retryableCheck.test(Throwables.getRootCause(e))) {
        log.debug("Retry attempt ({} of {}). Failure due to {}", attemptIndex, maxRetries, Throwables.getRootCause(e).getClass());
        scheduler.schedule(delayBetweenRetries.multipliedBy(2 ^ attemptIndex), () -> execute(operation, attemptIndex + 1, future));
      } else {
        future.completeExceptionally(e);
      }
    } else {
      future.complete(r);
    }
  });
}
 
Example #18
Source File: RecoveringSessionClient.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Override
public CompletableFuture<byte[]> execute(PrimitiveOperation operation) {
  SessionClient proxy = this.session;
  if (proxy != null) {
    return proxy.execute(operation);
  } else {
    return connectFuture.thenCompose(c -> c.execute(operation));
  }
}
 
Example #19
Source File: DefaultProxySession.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Override
public Object invoke(Object object, Method method, Object[] args) throws Throwable {
  OperationId operationId = operations.get(method);
  if (operationId != null) {
    future.set(session.execute(PrimitiveOperation.operation(operationId, encode(args)))
        .thenApply(DefaultProxySession.this::decode));
  } else {
    throw new PrimitiveException("Unknown primitive operation: " + method.getName());
  }
  return Defaults.defaultValue(method.getReturnType());
}
 
Example #20
Source File: ExecuteRequest.java    From atomix with Apache License 2.0 4 votes vote down vote up
public static ExecuteRequest request(PrimitiveDescriptor primitive, long session, MemberId node, PrimitiveOperation operation) {
  return new ExecuteRequest(primitive, session, node, operation);
}
 
Example #21
Source File: DelegatingSessionClient.java    From atomix with Apache License 2.0 4 votes vote down vote up
@Override
public CompletableFuture<byte[]> execute(PrimitiveOperation operation) {
  return session.execute(operation);
}
 
Example #22
Source File: QueryEntry.java    From atomix with Apache License 2.0 4 votes vote down vote up
public QueryEntry(long term, long timestamp, long session, long sequence, PrimitiveOperation operation) {
  super(term, timestamp, session, sequence, operation);
}
 
Example #23
Source File: OperationEntry.java    From atomix with Apache License 2.0 4 votes vote down vote up
public OperationEntry(long term, long timestamp, long session, long sequence, PrimitiveOperation operation) {
  super(term, timestamp, session);
  this.sequence = sequence;
  this.operation = operation;
}
 
Example #24
Source File: CommandEntry.java    From atomix with Apache License 2.0 4 votes vote down vote up
public CommandEntry(long term, long timestamp, long session, long sequence, PrimitiveOperation operation) {
  super(term, timestamp, session, sequence, operation);
}
 
Example #25
Source File: BlockingAwareSessionClient.java    From atomix with Apache License 2.0 4 votes vote down vote up
@Override
public CompletableFuture<byte[]> execute(PrimitiveOperation operation) {
  return asyncFuture(super.execute(operation), context);
}
 
Example #26
Source File: ExecuteRequest.java    From atomix with Apache License 2.0 4 votes vote down vote up
public ExecuteRequest(PrimitiveDescriptor primitive, long session, MemberId node, PrimitiveOperation operation) {
  super(primitive);
  this.session = session;
  this.node = node;
  this.operation = operation;
}
 
Example #27
Source File: ExecuteRequest.java    From atomix with Apache License 2.0 4 votes vote down vote up
public PrimitiveOperation operation() {
  return operation;
}
 
Example #28
Source File: ExecuteOperation.java    From atomix with Apache License 2.0 4 votes vote down vote up
public ExecuteOperation(long index, long timestamp, long session, MemberId node, PrimitiveOperation operation) {
  super(Type.EXECUTE, index, timestamp);
  this.session = session;
  this.node = node;
  this.operation = operation;
}
 
Example #29
Source File: ExecuteOperation.java    From atomix with Apache License 2.0 4 votes vote down vote up
public PrimitiveOperation operation() {
  return operation;
}
 
Example #30
Source File: OperationRequest.java    From atomix with Apache License 2.0 4 votes vote down vote up
protected OperationRequest(long session, long sequence, PrimitiveOperation operation) {
  super(session);
  this.sequence = sequence;
  this.operation = operation;
}