/*
*
* * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
* *
* * 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.
* *
* * For more information: http://www.orientechnologies.com
*
*/
package com.orientechnologies.orient.server.distributed.impl.task;
import com.orientechnologies.orient.core.command.*;
import com.orientechnologies.orient.core.db.ODatabaseDocumentInternal;
import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
import com.orientechnologies.orient.core.exception.ORetryQueryException;
import com.orientechnologies.orient.core.serialization.OStreamableHelper;
import com.orientechnologies.orient.core.sql.OCommandExecutorSQLDelegate;
import com.orientechnologies.orient.core.sql.OCommandExecutorSQLSelect;
import com.orientechnologies.orient.core.sql.OCommandSQL;
import com.orientechnologies.orient.core.sql.filter.OSQLTarget;
import com.orientechnologies.orient.server.OServer;
import com.orientechnologies.orient.server.distributed.ODistributedRequestId;
import com.orientechnologies.orient.server.distributed.ODistributedServerLog;
import com.orientechnologies.orient.server.distributed.ODistributedServerLog.DIRECTION;
import com.orientechnologies.orient.server.distributed.ODistributedServerManager;
import com.orientechnologies.orient.server.distributed.ORemoteTaskFactory;
import com.orientechnologies.orient.server.distributed.task.OAbstractCommandTask;
import com.orientechnologies.orient.server.distributed.task.ORemoteTask;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
/**
* Distributed task used for synchronization.
*
* @author Luca Garulli (l.garulli--at--orientechnologies.com)
*/
public class OSQLCommandTask extends OAbstractCommandTask {
private static final long serialVersionUID = 1L;
public static final int FACTORYID = 5;
protected String text;
protected Map<Object, Object> params;
protected RESULT_STRATEGY resultStrategy;
protected Collection<String> clusters;
protected OCommandDistributedReplicateRequest.QUORUM_TYPE quorumType;
protected long timeout;
protected boolean idempotent;
public OSQLCommandTask() {
clusters = new HashSet<String>();
}
public OSQLCommandTask(final OCommandRequestText iCommand, final Collection<String> iClusterNames) {
clusters = iClusterNames;
text = iCommand.getText();
params = iCommand.getParameters();
final OCommandExecutor executor = OCommandManager.instance().getExecutor(iCommand);
executor.parse(iCommand);
quorumType = ((OCommandDistributedReplicateRequest) executor).getQuorumType();
timeout = executor.getDistributedTimeout();
idempotent = executor.isIdempotent();
}
public Object execute(ODistributedRequestId requestId, final OServer iServer, ODistributedServerManager iManager,
final ODatabaseDocumentInternal database) throws Exception {
if (ODistributedServerLog.isDebugEnabled())
ODistributedServerLog
.debug(this, iManager.getLocalNodeName(), getNodeSource(), DIRECTION.IN, "Execute command=%s db=%s", text.toString(),
database.getName());
Object res;
while (true) {
try {
final OCommandRequest cmd = database.command(new OCommandSQL(text));
OCommandExecutor executor = OCommandManager.instance().getExecutor((OCommandRequestInternal) cmd);
executor.parse(cmd);
final OCommandExecutor exec = executor instanceof OCommandExecutorSQLDelegate ?
((OCommandExecutorSQLDelegate) executor).getDelegate() :
executor;
if (exec instanceof OCommandExecutorSQLSelect && clusters.size() > 0) {
// REWRITE THE TARGET TO USE CLUSTERS
final StringBuilder buffer = new StringBuilder("cluster:[");
int i = 0;
for (String c : clusters) {
if (i++ > 0)
buffer.append(',');
buffer.append(c);
}
buffer.append("]");
((OCommandExecutorSQLSelect) exec).setParsedTarget(new OSQLTarget(buffer.toString(), exec.getContext()));
}
if (params != null)
// EXECUTE WITH PARAMETERS
res = executor.execute(params);
else
res = executor.execute(null);
break;
} catch (ORetryQueryException e) {
continue;
}
}
return res;
}
public OCommandDistributedReplicateRequest.QUORUM_TYPE getQuorumType() {
return quorumType;
}
@Override
public RESULT_STRATEGY getResultStrategy() {
return resultStrategy;
}
public void setResultStrategy(final RESULT_STRATEGY resultStrategy) {
this.resultStrategy = resultStrategy;
}
@Override
public long getDistributedTimeout() {
return timeout;
}
@Override
public void toStream(final DataOutput out) throws IOException {
out.writeUTF(text);
OStreamableHelper.toStream(out, params);
out.writeInt(clusters.size());
for (String c : clusters)
out.writeUTF(c);
}
@Override
public void fromStream(final DataInput in, final ORemoteTaskFactory factory) throws IOException {
text = in.readUTF();
params = (Map<Object, Object>) OStreamableHelper.fromStream(in);
final int cSize = in.readInt();
clusters = new HashSet<String>(cSize);
for (int i = 0; i < cSize; ++i)
clusters.add(in.readUTF());
}
@Override
public String getName() {
return "command_sql";
}
@Override
public String toString() {
return super.toString() + "(" + text + ")";
}
@Override
public ORemoteTask getUndoTask(final ODistributedRequestId reqId) {
final OCommandRequest cmd = ODatabaseRecordThreadLocal.INSTANCE.get().command(new OCommandSQL(text));
OCommandExecutor executor = OCommandManager.instance().getExecutor((OCommandRequestInternal) cmd);
executor.parse(cmd);
if (executor instanceof OCommandExecutorSQLDelegate)
executor = ((OCommandExecutorSQLDelegate) executor).getDelegate();
if (executor instanceof OCommandDistributedReplicateRequest) {
final String undoCommand = ((OCommandDistributedReplicateRequest) executor).getUndoCommand();
if (undoCommand != null) {
final OSQLCommandTask undoTask = new OSQLCommandTask(new OCommandSQL(undoCommand), clusters);
undoTask.setResultStrategy(resultStrategy);
return undoTask;
}
}
return super.getUndoTask(reqId);
}
@Override
public boolean isIdempotent() {
return idempotent;
}
@Override
public int getFactoryId() {
return FACTORYID;
}
}