Package org.hivedb.meta.directory

Source Code of org.hivedb.meta.directory.DbDirectory

package org.hivedb.meta.directory;

import org.hivedb.DirectoryCorruptionException;
import org.hivedb.HiveKeyNotFoundException;
import org.hivedb.Lockable.Status;
import org.hivedb.meta.Node;
import org.hivedb.meta.PartitionDimension;
import org.hivedb.meta.Resource;
import org.hivedb.meta.SecondaryIndex;
import org.hivedb.meta.persistence.CachingDataSourceProvider;
import org.hivedb.util.QuickCache;
import org.hivedb.util.database.JdbcTypeMapper;
import org.hivedb.util.database.RowMappers;
import org.hivedb.util.database.Schemas;
import org.hivedb.util.database.Statements;
import org.hivedb.util.functional.Atom;
import org.hivedb.util.functional.Delay;
import org.hivedb.util.functional.Unary;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import javax.sql.DataSource;
import java.sql.Types;
import java.util.Collection;
import java.util.Map;

public class DbDirectory extends SimpleJdbcDaoSupport implements NodeResolver, Directory {
  private static QuickCache cache = new QuickCache();
  private PartitionDimension partitionDimension;
  private IndexSqlFormatter sql = new IndexSqlFormatter();


  public DbDirectory(PartitionDimension dimension, DataSource dataSource) {
    this.partitionDimension = dimension;
    this.setDataSource(dataSource);
  }

  public DbDirectory(PartitionDimension dimension) {
    this.partitionDimension = dimension;
    this.setDataSource(CachingDataSourceProvider.getInstance().getDataSource(dimension.getIndexUri()));
  }

  public PartitionDimension getPartitionDimension() {
    return this.partitionDimension;
  }

  public Object insertPrimaryIndexKey(final Node node, final Object primaryIndexKey) {
    return newTransaction().execute(new TransactionCallback() {
      public Object doInTransaction(TransactionStatus arg0) {
        int[] types = new int[]{JdbcTypeMapper.primitiveTypeToJdbcType(primaryIndexKey.getClass()), Types.INTEGER};
        Object[] parameters = new Object[]{primaryIndexKey, node.getId()};

        if (lockPrimaryKeyForInsert(primaryIndexKey, node))
          doUpdate(sql.insertPrimaryIndexKey(partitionDimension), types, parameters);
        return primaryIndexKey;
      }
    });
  }

  public Object insertSecondaryIndexKey(final SecondaryIndex secondaryIndex, final Object secondaryIndexKey, final Object resourceId) {
    return newTransaction().execute(new TransactionCallback() {
      public Object doInTransaction(TransactionStatus arg0) {
        return insertSecondaryIndexKeyNoTransaction(secondaryIndex, secondaryIndexKey, resourceId);
      }
    });
  }

  Object insertSecondaryIndexKeyNoTransaction(final SecondaryIndex secondaryIndex, final Object secondaryIndexKey, final Object resourceId) {
    Object[] parameters = new Object[]{secondaryIndexKey, resourceId};
    int[] types = new int[]{secondaryIndex.getColumnInfo().getColumnType(), secondaryIndex.getResource().getColumnType()};

    if (lockSecondaryIndexKey(secondaryIndex, secondaryIndexKey, resourceId))
      doUpdate(sql.insertSecondaryIndexKey(secondaryIndex), types, parameters);
    return secondaryIndexKey;
  }

  public Object updatePrimaryIndexKeyReadOnly(final Object primaryIndexKey, final boolean isReadOnly) {
    return newTransaction().execute(new TransactionCallback() {
      public Object doInTransaction(TransactionStatus arg0) {
        Object[] parameters = new Object[]{isReadOnly, primaryIndexKey};
        int[] types = new int[]{Types.BOOLEAN, JdbcTypeMapper.primitiveTypeToJdbcType(primaryIndexKey.getClass())};
        lockPrimaryKeyForUpdate(primaryIndexKey);
        doUpdate(sql.updateReadOnlyOfPrimaryIndexKey(partitionDimension), types, parameters);
        return primaryIndexKey;
      }
    });
  }

  public Object updatePrimaryIndexKeyOfResourceId(final Resource resource, final Object resourceId, final Object newPrimaryIndexKey) {
    return newTransaction().execute(new TransactionCallback() {
      public Object doInTransaction(TransactionStatus arg0) {
        Object[] parameters = new Object[]{newPrimaryIndexKey, resourceId};
        int[] types = new int[]{
            JdbcTypeMapper.primitiveTypeToJdbcType(newPrimaryIndexKey.getClass()),
            resource.getColumnType()
        };
        lockResourceId(resource, resourceId);
        doUpdate(sql.updateResourceId(resource), types, parameters);
        return resourceId;
      }
    });
  }

  public void deletePrimaryIndexKey(final Object primaryIndexKey) {
    for (Resource resource : getPartitionDimension().getResources()) {
      if (!resource.isPartitioningResource())
        for (Object resourceId : getResourceIdsOfPrimaryIndexKey(resource, primaryIndexKey)) {
          deleteResourceId(resource, resourceId);
        }
      else
        batch().deleteAllSecondaryIndexKeysOfResourceId(resource, primaryIndexKey);
    }

    newTransaction().execute(new TransactionCallback() {
      public Object doInTransaction(TransactionStatus arg0) {
        lockPrimaryKeyForUpdate(primaryIndexKey);
        doUpdate(
            sql.deletePrimaryIndexKey(partitionDimension),
            new int[]{JdbcTypeMapper.primitiveTypeToJdbcType(primaryIndexKey.getClass())},
            new Object[]{primaryIndexKey});
        return primaryIndexKey;
      }
    });
  }


  public void deleteSecondaryIndexKey(final SecondaryIndex secondaryIndex, final Object secondaryIndexKey, final Object resourceId) {
    newTransaction().execute(new TransactionCallback() {
      public Object doInTransaction(TransactionStatus arg0) {
        return deleteSecondaryIndexKeyNoTransaction(secondaryIndex, secondaryIndexKey, resourceId);
      }
    });
  }

  Object deleteSecondaryIndexKeyNoTransaction(final SecondaryIndex secondaryIndex, final Object secondaryIndexKey, final Object resourceId) {
    Object[] parameters = new Object[]{secondaryIndexKey, resourceId};
    int[] types = new int[]{
        secondaryIndex.getColumnInfo().getColumnType(),
        JdbcTypeMapper.primitiveTypeToJdbcType(resourceId.getClass())
    };
    lockSecondaryIndexKey(secondaryIndex, secondaryIndexKey, resourceId);
    doUpdate(sql.deleteSingleSecondaryIndexKey(secondaryIndex), types, parameters);
    return secondaryIndexKey;
  }

  @SuppressWarnings("unchecked")
  public boolean doesPrimaryIndexKeyExist(Object primaryIndexKey) {
    Collection count = doRead(sql.checkExistenceOfPrimaryKey(partitionDimension),
        new Object[]{primaryIndexKey},
        RowMappers.newTrueRowMapper());
    return count.size() > 0;
  }

  public Collection<KeySemaphore> getKeySemamphoresOfPrimaryIndexKey(Object primaryIndexKey) {
    return doRead(sql.selectKeySemaphoreOfPrimaryIndexKey(partitionDimension),
        new Object[]{primaryIndexKey},
        new KeySemaphoreRowMapper());
  }

  public boolean doesResourceIdExist(Resource resource, Object resourceId) {
    if (resource.isPartitioningResource())
      return doesPrimaryIndexKeyExist(resourceId);
    Collection<Object> count =
        doRead(
            sql.checkExistenceOfResourceIndexSql(resource.getIdIndex()),
            new Object[]{resourceId},
            RowMappers.newTrueRowMapper());
    return count.size() > 0;
  }


  public boolean doesSecondaryIndexKeyExist(SecondaryIndex secondaryIndex, Object secondaryIndexKey, Object resourceId) {
    Collection<Object> count = doRead(
        sql.checkExistenceOfSecondaryIndexSql(secondaryIndex),
        new Object[]{secondaryIndexKey, resourceId},
        RowMappers.newTrueRowMapper());
    return count.size() > 0;
  }

  public Collection<KeySemaphore> getKeySemaphoresOfSecondaryIndexKey(SecondaryIndex secondaryIndex, Object secondaryIndexKey) {
    return doRead(
        sql.selectKeySemaphoresOfSecondaryIndexKey(secondaryIndex),
        new Object[]{secondaryIndexKey},
        new KeySemaphoreRowMapper());
  }

  @SuppressWarnings("unchecked")
  public Collection<KeySemaphore> getKeySemaphoresOfResourceId(Resource resource, Object resourceId) {
    return (Collection<KeySemaphore>) (resource.isPartitioningResource()
        ? getKeySemamphoresOfPrimaryIndexKey(resourceId)
        : doRead(
        sql.selectKeySemaphoresOfResourceId(resource),
        new Object[]{resourceId},
        new KeySemaphoreRowMapper()));
  }

  public Collection<Object> getPrimaryIndexKeysOfSecondaryIndexKey(SecondaryIndex secondaryIndex, Object secondaryIndexKey) {
    return doRead(
        sql.selectPrimaryIndexKeysOfSecondaryIndexKey(secondaryIndex),
        new Object[]{secondaryIndexKey},
        RowMappers.newObjectRowMapper(secondaryIndex.getResource().getPartitionDimension().getColumnType()));
  }

  public Collection<Object> getSecondaryIndexKeysOfPrimaryIndexKey(SecondaryIndex secondaryIndex, Object primaryIndexKey) {
    return doRead(
        sql.selectSecondaryIndexKeysOfPrimaryKey(secondaryIndex),
        new Object[]{primaryIndexKey},
        RowMappers.newObjectRowMapper(secondaryIndex.getColumnInfo().getColumnType()));
  }

  public void deleteResourceId(final Resource resource, final Object id) {
    //todo:
    //    directory.batch().deleteAllSecondaryIndexKeysOfResourceId(getResource(resource), id);
    newTransaction().execute(new TransactionCallback() {
      public Object doInTransaction(TransactionStatus arg0) {
        lockResourceId(resource, id);
        doUpdate(sql.deleteResourceId(resource), new int[]{resource.getColumnType()}, new Object[]{id});
        return id;
      }
    });
  }

  @SuppressWarnings("unchecked")
  public Collection getResourceIdsOfSecondaryIndexKey(SecondaryIndex secondaryIndex, Object secondaryIndexKey) {
    return doRead(
        sql.selectResourceIdsOfSecondaryIndexKey(secondaryIndex),
        new Object[]{secondaryIndexKey},
        RowMappers.newObjectRowMapper(secondaryIndex.getResource().getColumnType()));
  }

  @SuppressWarnings("unchecked")
  public Collection getResourceIdsOfPrimaryIndexKey(Resource resource, Object primaryIndexKey) {
    return doRead(
        sql.selectResourceIdsOfPrimaryIndexKey(resource.getIdIndex()),
        new Object[]{primaryIndexKey},
        RowMappers.newObjectRowMapper(resource.getColumnType()));
  }

  @SuppressWarnings("unchecked")
  public Collection getSecondaryIndexKeysOfResourceId(SecondaryIndex secondaryIndex, Object id) {
    return doRead(
        sql.selectSecondaryIndexKeyOfResourceId(secondaryIndex),
        new Object[]{id},
        RowMappers.newObjectRowMapper(secondaryIndex.getColumnInfo().getColumnType()));
  }

  @SuppressWarnings("unchecked")
  private <T> Collection<T> doRead(String sql, Object[] parameters, RowMapper mapper) {
    try {
      return (Collection<T>) getJdbcTemplate().query(sql, parameters, mapper);
    } catch (EmptyResultDataAccessException e) {
      throw new HiveKeyNotFoundException(String.format("Directory query returned no results. %s with parameters: %s", sql, parameters), e);
    }
  }

  private void doUpdate(String sql, int[] types, Object[] parameters) {
    getJdbcTemplate().update(Statements.newStmtCreatorFactory(sql, types).newPreparedStatementCreator(parameters));
  }

  public Object insertResourceId(final Resource resource, final Object id, final Object primaryIndexKey) {
    return newTransaction().execute(new TransactionCallback() {
      public Object doInTransaction(TransactionStatus arg0) {
        if (lockResourceId(resource, id))
          doUpdate(sql.insertResourceId(resource),
              new int[]{resource.getColumnType(), resource.getPartitionDimension().getColumnType()},
              new Object[]{id, primaryIndexKey});
        return id;
      }
    });
  }

  @SuppressWarnings("unchecked")
  public Object getPrimaryIndexKeyOfResourceId(Resource resource, Object id) {
    Collection keys = doRead(
        sql.selectPrimaryIndexKeysOfResourceId(resource),
        new Object[]{id},
        RowMappers.newObjectRowMapper(resource.getPartitionDimension().getColumnType()));
    if (keys.size() == 0)
      throw new HiveKeyNotFoundException(String.format("Unable to find primary key for resource %s with id %s", resource.getName(), id), id);
    else if (keys.size() > 1)
      throw new DirectoryCorruptionException(String.format("Directory corruption: Resource %s with id %s is owned more than one primary key.", resource.getName(), id));
    return Atom.getFirstOrNull(keys);
  }

  public Object insertSecondaryIndexKeys(Map<SecondaryIndex, Collection<Object>> secondaryIndexValueMap, Object resourceId) {
    //todo: finish
    return batch().insertSecondaryIndexKeys(secondaryIndexValueMap, resourceId);
  }

  public void deleteSecondaryIndexKeys(Map<SecondaryIndex, Collection<Object>> secondaryIndexValueMap, Object resourceId) {
    //todo: complete this
    batch().deleteSecondaryIndexKeys(secondaryIndexValueMap, resourceId);
  }

  public Unary<KeySemaphore, Integer> semaphoreToId() {
    return new Unary<KeySemaphore, Integer>() {

      public Integer f(KeySemaphore item) {
        return item.getNodeId();
      }
    };
  }

  public Unary<KeySemaphore, Boolean> semaphoreToReadOnly() {
    return new Unary<KeySemaphore, Boolean>() {

      public Boolean f(KeySemaphore item) {
        return !item.getStatus().equals(Status.writable);
      }
    };
  }

  public BatchIndexWriter batch() {
    final DbDirectory d = this;
    return cache.get(BatchIndexWriter.class, new Delay<BatchIndexWriter>() {
      public BatchIndexWriter f() {
        return new BatchIndexWriter(d);
      }
    });
  }

  private void setTransactionManager(TransactionTemplate transactionTemplate, final JdbcDaoSupport jdbcDaoSupport) {
    transactionTemplate.setTransactionManager((DataSourceTransactionManager) cache.get(jdbcDaoSupport.getDataSource(), new Delay<DataSourceTransactionManager>() {
      public DataSourceTransactionManager f() {
        return new DataSourceTransactionManager(jdbcDaoSupport.getDataSource());
      }
    }));
  }

  private boolean lockPrimaryKeyForInsert(Object primaryIndexKey, Node node) {
    return doRead(sql.selectCompositeKeyForUpdateLock(Schemas.getPrimaryIndexTableName(partitionDimension), "id", "node"),
        new Object[]{primaryIndexKey, node.getId()},
        RowMappers.newTrueRowMapper()).size() == 0;
  }

  private boolean lockPrimaryKeyForUpdate(Object primaryIndexKey) {
    return doRead(sql.selectForUpdateLock(Schemas.getPrimaryIndexTableName(partitionDimension), "id"),
        new Object[]{primaryIndexKey},
        RowMappers.newTrueRowMapper()).size() == 0;
  }

  private boolean lockSecondaryIndexKey(SecondaryIndex secondaryIndex, Object secondaryIndexKey, Object resourceId) {
    return doRead(sql.selectCompositeKeyForUpdateLock(Schemas.getSecondaryIndexTableName(secondaryIndex), "id", "pkey"),
        new Object[]{secondaryIndexKey, resourceId},
        RowMappers.newTrueRowMapper()).size() == 0;
  }

  private boolean lockResourceId(Resource resource, Object resourceId) {
    return doRead(sql.selectForUpdateLock(Schemas.getResourceIndexTableName(resource), "id"),
        new Object[]{resourceId},
        RowMappers.newTrueRowMapper()).size() == 0;
  }

  public TransactionTemplate newTransaction() {
    TransactionTemplate t = new TransactionTemplate();
    setTransactionManager(t, this);
    return t;
  }
}
TOP

Related Classes of org.hivedb.meta.directory.DbDirectory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.