/* * Galaxy * Copyright (c) 2012-2014, Parallel Universe Software Co. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 3.0 * as published by the Free Software Foundation. */ package co.paralleluniverse.galaxy.core; import co.paralleluniverse.common.io.Persistable; import co.paralleluniverse.common.util.Enums; import co.paralleluniverse.galaxy.Grid; import com.google.common.util.concurrent.AbstractFuture; import com.google.common.util.concurrent.ListenableFuture; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * * @author pron */ class Op { public enum Type { GET, INVOKE, GETS, GETX, GET_FROM_OWNER, SET, PUT, ALLOC, DEL, SEND, PUSH, PUSHX, LSTN; public boolean isOf(long set) { return Enums.isIn(this, set); } } private static final byte COMPLETED = 1; private static final byte CANCELLED = 2; public final Type type; public final long line; public final Transaction txn; public final Object data; private Object extra; private OpFuture<Object> future; private long startTime; private byte status; Op(Type type, long line, Object data, Object extra, Transaction txn) { this.type = type; this.line = line; if (data != null && data instanceof byte[]) data = Arrays.copyOf(((byte[]) data), ((byte[]) data).length); this.data = data; this.txn = txn; this.extra = extra; } public Op(Type type, long line, byte[] data, Object extra, Transaction txn) { this(type, line, (Object) data, extra, txn); } public Op(Type type, long line, ByteBuffer data, Object extra, Transaction txn) { this(type, line, (Object) data, extra, txn); } public Op(Type type, long line, Persistable data, Object extra, Transaction txn) { this(type, line, (Object) data, extra, txn); } public Op(Type type, long line, byte[] data, Transaction txn) { this(type, line, data, null, txn); } public Op(Type type, long line, ByteBuffer data, Transaction txn) { this(type, line, data, null, txn); } public Op(Type type, long line, Persistable data, Transaction txn) { this(type, line, data, null, txn); } public Op(Type type, long line, Object extra, Transaction txn) { this(type, line, (Object) null, extra, txn); } public Op(Type type, long line, Transaction txn) { this(type, line, (Object) null, null, txn); } public Object getExtra() { return extra; } public void setExtra(Object extra) { this.extra = extra; } void createFuture() { assert future == null; this.future = new OpFuture<Object>(this); } public boolean hasFuture() { return future != null; } public ListenableFuture<Object> getFuture() { return future; } public void setResult(Object result) { setCompleted(); future.set(result); } public void setException(Throwable t) { setCompleted(); future.setException(t); } public Object getResult() throws InterruptedException, ExecutionException { return future.get(); } public Object getResult(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return future.get(timeout, unit); } public long getStartTime() { return startTime; } public void setStartTime(long startTime) { this.startTime = startTime; } void setCancelled() { assert status == 0; this.status = CANCELLED; } private void setCompleted() { assert status == 0; this.status = COMPLETED; } public boolean isCancelled() { return status == CANCELLED; } public boolean isCompleted() { return status == COMPLETED; } @Override public boolean equals(Object obj) { if (obj == null) return false; if (getClass() != obj.getClass()) return false; final Op other = (Op) obj; if (this.type != other.type) return false; if (this.line != other.line) return false; if (!Objects.equals(this.data, other.data)) return false; if (!Objects.equals(this.extra, other.extra)) return false; return true; } @Override public int hashCode() { int hash = 3; hash = 89 * hash + (this.type != null ? this.type.hashCode() : 0); hash = 89 * hash + (int) (this.line ^ (this.line >>> 32)); hash = 89 * hash + Objects.hashCode(this.data); hash = 89 * hash + Objects.hashCode(this.extra); return hash; } @Override public String toString() { return "Op." + type + "(line:" + Long.toHexString(line) + (data != null ? ", data:" + data : "") + (extra != null ? ", extra:" + extra : "") + ')'; } private static final class OpFuture<V> extends AbstractFuture<V> { private final Op op; OpFuture(Op op) { this.op = op; } @Override public boolean cancel(boolean mayInterruptIfRunning) { if (!getCache().cancelOp(op)) return false; assert op.isCancelled(); return super.cancel(mayInterruptIfRunning); } @Override public boolean set(V value) { return super.set(value); } @Override public boolean setException(Throwable throwable) { return super.setException(throwable); } } static Cache getCache() { try { return ((StoreImpl) Grid.getInstance().store()).cache; } catch (InterruptedException e) { throw new AssertionError(e); } } }