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

io.snappydata.thrift.common.ThriftUtils Maven / Gradle / Ivy

There is a newer version: 1.6.7
Show newest version
/*
 * Copyright (c) 2010-2015 Pivotal Software, 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.
 */
/*
 * Changes for SnappyData data platform.
 *
 * Portions Copyright (c) 2017-2019 TIBCO Software 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.common;

import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.EnumMap;

import com.gemstone.gemfire.internal.shared.ClientSharedData;
import com.gemstone.gemfire.internal.shared.ClientSharedUtils;
import com.gemstone.gemfire.internal.shared.SystemProperties;
import com.gemstone.gemfire.internal.shared.unsafe.DirectBufferAllocator;
import com.pivotal.gemfirexd.Attribute;
import com.pivotal.gemfirexd.internal.shared.common.SharedUtils;
import io.snappydata.thrift.HostAddress;
import io.snappydata.thrift.TransactionAttribute;
import org.apache.thrift.transport.TNonblockingTransport;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;

/**
 * Some Thrift utility methods shared by client and server code. Only has static
 * methods so no instance allowed.
 */
public abstract class ThriftUtils {

  /**
   * no instance allowed
   */
  private ThriftUtils() {
  }

  public static boolean isThriftSelectorServer() {
    return SystemProperties.getServerInstance().getBoolean(
        Attribute.THRIFT_SELECTOR_SERVER, false);
  }

  public static HostAddress getHostAddress(final String hostNameAndAddress,
      final int port) {
    final int slashIndex = hostNameAndAddress.indexOf('/');
    if (slashIndex > 0) {
      final String hostName = hostNameAndAddress.substring(0, slashIndex);
      final String ipAddress = hostNameAndAddress.substring(slashIndex + 1);
      if (ipAddress.length() > 0 && !hostName.equals(ipAddress)) {
        return new HostAddress(hostName, port).setIpAddress(ipAddress);
      } else {
        return new HostAddress(hostName, port);
      }
    } else if (slashIndex == 0) {
      return new HostAddress(hostNameAndAddress.substring(1), port);
    } else {
      return new HostAddress(hostNameAndAddress, port);
    }
  }

  private static final SharedUtils.CSVVisitor
      parseSSLParams = new SharedUtils.CSVVisitor() {
    @Override
    public void visit(String str, SocketParameters sslParams, Void ignore) {
      int eqIndex = str.indexOf('=');
      if (eqIndex > 0) {
        String key = str.substring(0, eqIndex).trim();
        String value = str.substring(eqIndex + 1).trim();
        try {
          SocketParameters.findSSLParameterByPropertyName(key).setParameter(
              sslParams, value);
        } catch (NumberFormatException nfe) {
          throw new IllegalArgumentException(
              "Expected numeric format for SSL property '" + key +
                  "' but got: " + value, nfe);
        }
      } else {
        throw new IllegalArgumentException("Missing equality: expected "
            + "comma-separated = pairs");
      }
    }
  };

  /**
   * Convert comma-separated list of SSL key, value pairs into thrift SSL
   * parameters list.
   */
  public static void getSSLParameters(SocketParameters socketParams,
      String sslProperties) {
    if (sslProperties != null && sslProperties.length() > 0) {
      socketParams.setHasSSLParams();
      SharedUtils.splitCSV(sslProperties, parseSSLParams, socketParams, null);
    }
  }

  public static EnumMap newTransactionFlags() {
    return new EnumMap<>(TransactionAttribute.class);
  }

  public static byte[] toBytes(ByteBuffer buffer) {
    return ClientSharedUtils.toBytes(buffer);
  }

  public static ByteBuffer readByteBuffer(TNonblockingTransport transport,
      int length) throws TTransportException {
    if (length == 0) {
      return ClientSharedData.NULL_BUFFER;
    }
    if (transport.getBytesRemainingInBuffer() >= length) {
      ByteBuffer buffer = ByteBuffer.wrap(transport.getBuffer(),
          transport.getBufferPosition(), length);
      transport.consumeBuffer(length);
      return buffer;
    }

    // use normal byte array if length is not large since direct byte buffer
    // has additional overheads of allocation and finalization
    if (length <= (SocketParameters.DEFAULT_BUFFER_SIZE >>> 2)) {
      byte[] buffer = new byte[length];
      transport.readAll(buffer, 0, length);
      return ByteBuffer.wrap(buffer);
    }

    // this might be too big for ByteBuffer.allocateDirect -- see
    // sun.misc.VM.maxDirectMemory()
    ByteBuffer buffer;
    try {
      buffer = DirectBufferAllocator.instance().allocateWithFallback(
          length, "THRIFT");
    } catch (OutOfMemoryError | RuntimeException ignored) {
      // fallback to heap buffer
      buffer = ByteBuffer.allocate(length);
    }
    buffer.limit(length);
    try {
      long parkedNanos = 0L;
      int numTries = 0;
      while (length > 0) {
        int numReadBytes = transport.read(buffer);
        if (numReadBytes > 0) {
          length -= numReadBytes;
        } else if (numReadBytes == 0) {
          // sleep a bit after some retries
          // TODO: this should use selector signal if available
          parkedNanos = ClientSharedUtils.parkThreadForAsyncOperationIfRequired(
              null, parkedNanos, ++numTries);
        } else {
          throw new EOFException("Socket channel closed in read.");
        }
      }
    } catch (IOException e) {
      throw new TTransportException(e instanceof EOFException
          ? TTransportException.END_OF_FILE : TTransportException.UNKNOWN);
    }
    buffer.flip();
    return buffer;
  }

  public static void writeByteBuffer(ByteBuffer buffer,
      TTransport transport, TNonblockingTransport nonBlockingTransport,
      int length) throws TTransportException {
    if (buffer.hasArray()) {
      transport.write(buffer.array(), buffer.position() + buffer.arrayOffset(),
          length);
    } else if (nonBlockingTransport != null) {
      try {
        long parkedNanos = 0L;
        int numTries = 0;
        final int position = buffer.position();
        boolean flushed = false;
        while (length > 0) {
          int numWrittenBytes = nonBlockingTransport.write(buffer);
          if (numWrittenBytes > 0) {
            length -= numWrittenBytes;
          } else if (numWrittenBytes == 0) {
            // flush the buffers before retry
            if (!flushed) {
              nonBlockingTransport.flush();
              flushed = true;
            } else {
              // sleep a bit after some retries
              flushed = false;
              parkedNanos = ClientSharedUtils.parkThreadForAsyncOperationIfRequired(
                  null, parkedNanos, ++numTries);
            }
          } else {
            throw new EOFException("Socket channel closed in write.");
          }
        }
        // move back to original position
        buffer.position(position);
      } catch (IOException e) {
        throw new TTransportException(e instanceof EOFException
            ? TTransportException.END_OF_FILE : TTransportException.UNKNOWN);
      }
    } else {
      final byte[] bytes = ClientSharedUtils.toBytes(
          buffer, buffer.remaining(), length);
      transport.write(bytes, 0, length);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy