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

com.truward.kvdao.xodus.KeyUtil Maven / Gradle / Ivy

There is a newer version: 0.0.2
Show newest version
package com.truward.kvdao.xodus;

import com.google.protobuf.Message;
import com.truward.semantic.id.IdCodec;
import jetbrains.exodus.ArrayByteIterable;
import jetbrains.exodus.ByteIterable;
import jetbrains.exodus.env.Store;
import jetbrains.exodus.env.Transaction;
import org.springframework.util.StringUtils;

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Arrays;
import java.util.Random;
import java.util.function.BiFunction;
import java.util.function.Supplier;

import static com.truward.kvdao.xodus.ProtoEntity.protoToEntry;

/**
 * Utility class for operating on Xodus Keys.
 *
 * @author Alexander Shabanov
 */
@ParametersAreNonnullByDefault
public final class KeyUtil {

  /**
   * Default size of byte array backing the key.
   * The value is picked up to exclude potential clashes.
   */
  public static final int DEFAULT_KEY_BYTES_SIZE = 16;

  private KeyUtil() {}

  public static ByteIterable semanticIdAsKey(IdCodec codec, String id) {
    return new ArrayByteIterable(codec.decodeBytes(id));
  }

  public static String keyAsSemanticId(IdCodec codec, ByteIterable key) {
    byte[] keyBytes = key.getBytesUnsafe();
    if (keyBytes.length > key.getLength()) {
      keyBytes = Arrays.copyOf(keyBytes, key.getLength());
    }
    return codec.encodeBytes(keyBytes);
  }

  public static void assertValidId(IdCodec codec, String id, Supplier messageSupplier) {
    if (codec.canDecode(id)) {
      return;
    }

    throw new IllegalArgumentException(messageSupplier.get());
  }

  public static void assertValidOptionalId(IdCodec codec, @Nullable String id, Supplier messageSupplier) {
    if (StringUtils.hasLength(id)) {
      assertValidId(codec, id, messageSupplier);
    }
  }

  public static  T addUniqueEntry(
      Transaction tx,
      Store entryStore,
      T entry,
      BiFunction idApplier,
      IdCodec entryKeyCodec,
      int startKeySize,
      Random keyRandom) {
    assert startKeySize > 0 && startKeySize < KeyUtil.DEFAULT_KEY_BYTES_SIZE;

    for (int keySize = startKeySize; keySize < KeyUtil.DEFAULT_KEY_BYTES_SIZE; ++keySize) {
      final byte[] keyBytes = new byte[keySize];
      keyRandom.nextBytes(keyBytes);

      final String id = entryKeyCodec.encodeBytes(keyBytes);
      entry = idApplier.apply(entry, id);

      // try adding as new item
      // TODO: this needs to be much smarter in multi-threaded environment,
      // TODO:    e.g. it requires cluster ID at the beginning of small IDs
      final ByteIterable idKey = new ArrayByteIterable(keyBytes);
      if (entryStore.add(tx, idKey, protoToEntry(entry))) {
        break;
      }
    }

    return entry;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy