All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.snappydata.thrift.internal.datasource.ClientXAResource Maven / Gradle / Ivy

/*
 * Copyright (c) 2017 SnappyData, Inc. All rights reserved.
 *
 * 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. See accompanying
 * LICENSE file.
 */
package io.snappydata.thrift.internal.datasource;

import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import com.pivotal.gemfirexd.internal.shared.common.reference.SQLState;
import io.snappydata.thrift.SnappyException;
import io.snappydata.thrift.SnappyExceptionData;
import io.snappydata.thrift.TransactionXid;
import io.snappydata.thrift.common.ThriftExceptionUtil;
import io.snappydata.thrift.internal.ClientService;
import io.snappydata.thrift.internal.HostConnection;

/**
 * {@link XAResource} implementation for a thrift based connection.
 */
public class ClientXAResource extends ReentrantLock implements XAResource {

  private final ClientService clientService;
  private int timeoutInSeconds;
  private HostConnection txHost;

  ClientXAResource(ClientService service) {
    this.clientService = service;
  }

  private XAException newXAException(int xaCode, String sqlState,
      Object... args) {
    XAException xae = new XAException(xaCode);
    if (sqlState != null) {
      xae.initCause(ThriftExceptionUtil.newSQLException(sqlState, null, args));
    }
    return xae;
  }

  private XAException newXAException(SnappyException se) {
    XAException xae;
    SnappyExceptionData data = se.getExceptionData();
    final String sqlState = data.getSqlState();
    if (sqlState == null || sqlState.isEmpty()) {
      String message = data.getReason();
      if (message != null) {
        xae = new XAException(message);
        xae.errorCode = data.getErrorCode();
      } else {
        xae = new XAException(data.errorCode);
      }
    } else {
      xae = new XAException(XAException.XAER_RMERR);
    }
    xae.initCause(ThriftExceptionUtil.newSQLException(se));
    return xae;
  }

  private void checkClosedConnection(ClientService service)
      throws XAException {
    if (service.isClosed()) {
      throw newXAException(XAException.XAER_RMFAIL,
          SQLState.NO_CURRENT_CONNECTION);
    }
  }

  private void initTXHost(ClientService service) {
    if (service != null) {
      this.txHost = service.getCurrentHostConnection();
    } else {
      this.txHost = null;
    }
  }

  private HostConnection getTXHost() throws XAException {
    final HostConnection txHost = this.txHost;
    if (txHost != null) {
      return txHost;
    } else {
      throw new XAException(XAException.XAER_PROTO);
    }
  }

  private TransactionXid transactionXid(Xid xid) {
    return new TransactionXid(xid.getFormatId(),
        ByteBuffer.wrap(xid.getGlobalTransactionId()),
        ByteBuffer.wrap(xid.getBranchQualifier()));
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public boolean setTransactionTimeout(int seconds) throws XAException {
    if (seconds < 0) {
      // throw an exception if invalid value was specified
      throw new XAException(XAException.XAER_INVAL);
    }
    this.timeoutInSeconds = seconds;
    return true;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public int getTransactionTimeout() {
    return this.timeoutInSeconds;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isSameRM(XAResource xaResource) throws XAException {
    checkClosedConnection(this.clientService);
    if (xaResource instanceof ClientXAResource) {
      ClientXAResource otherResource = (ClientXAResource)xaResource;
      if (this.clientService == otherResource.clientService) {
        return true;
      }
      HostConnection otherConn = otherResource.txHost;
      HostConnection conn = this.txHost;
      if (otherConn == null) {
        otherConn = otherResource.clientService.getCurrentHostConnection();
      }
      if (conn == null) {
        conn = this.clientService.getCurrentHostConnection();
      }
      return (conn != null && conn.equals(otherConn));
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void start(Xid xid, int flags) throws XAException {
    final ClientService service = this.clientService;
    super.lock();
    try {
      checkClosedConnection(service);
      service.startXATransaction(transactionXid(xid),
          this.timeoutInSeconds, flags);
      initTXHost(service);
    } catch (SnappyException se) {
      throw newXAException(se);
    } finally {
      super.unlock();
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public int prepare(Xid xid) throws XAException {
    final HostConnection txHost = getTXHost();
    final ClientService service = this.clientService;
    super.lock();
    try {
      checkClosedConnection(service);
      return service.prepareXATransaction(txHost, transactionXid(xid));
    } catch (SnappyException se) {
      throw newXAException(se);
    } finally {
      super.unlock();
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void commit(Xid xid, boolean onePhase) throws XAException {
    final HostConnection txHost = getTXHost();
    final ClientService service = this.clientService;
    super.lock();
    try {
      checkClosedConnection(service);
      service.commitXATransaction(txHost, transactionXid(xid), onePhase);
    } catch (SnappyException se) {
      throw newXAException(se);
    } finally {
      super.unlock();
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void rollback(Xid xid) throws XAException {
    final HostConnection txHost = getTXHost();
    final ClientService service = this.clientService;
    super.lock();
    try {
      checkClosedConnection(service);
      service.rollbackXATransaction(txHost, transactionXid(xid));
    } catch (SnappyException se) {
      throw newXAException(se);
    } finally {
      super.unlock();
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void end(Xid xid, int flags) throws XAException {
    final HostConnection txHost = getTXHost();
    final ClientService service = this.clientService;
    super.lock();
    try {
      checkClosedConnection(service);
      service.endXATransaction(txHost, transactionXid(xid), flags);
    } catch (SnappyException se) {
      throw newXAException(se);
    } finally {
      super.unlock();
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void forget(Xid xid) throws XAException {
    final HostConnection txHost = getTXHost();
    final ClientService service = this.clientService;
    super.lock();
    try {
      checkClosedConnection(service);
      service.forgetXATransaction(txHost, transactionXid(xid));
    } catch (SnappyException se) {
      throw newXAException(se);
    } finally {
      super.unlock();
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Xid[] recover(int flag) throws XAException {
    final HostConnection txHost = getTXHost();
    final ClientService service = this.clientService;
    super.lock();
    try {
      checkClosedConnection(service);
      List xidList = service.recoverXATransaction(txHost, flag);
      final Xid[] resultXids = new Xid[xidList.size()];
      for (int index = 0; index < resultXids.length; index++) {
        resultXids[index] = new ClientXid(xidList.get(index));
      }
      return resultXids;
    } catch (SnappyException se) {
      throw newXAException(se);
    } finally {
      super.unlock();
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy