package de.hub.emffrag.hbase; import static de.hub.emffrag.hbase.HBaseUtil.col; import static de.hub.emffrag.hbase.HBaseUtil.colFamily; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import com.google.common.base.Throwables; import de.hub.emffrag.EmfFragActivator; import de.hub.emffrag.datastore.IBaseDataStore; import de.hub.emffrag.datastore.IBulkInsertExtension; import de.hub.emffrag.datastore.IScanExtension; /** * HBase implementation of {@link DataStore}. This implementation currently only * works for HBase running on localhost. */ public class HBaseDataStore implements IBaseDataStore, IBulkInsertExtension, IScanExtension { private int scanCacheSize = 1000; private final String dataStoreId; private final boolean deleteExistingTable; private HTable hTable; /** * @param dataStoreId * Each model is covered by one table. This parameter is the * table name. */ public HBaseDataStore(String dataStoreId) { this(dataStoreId, false); } /** * see {@link #HBaseDataStore(String)} * * @param deleteExistingTable * if true and the table dataStoreId already exists it gets * deleted first. */ public HBaseDataStore(String dataStoreId, boolean deleteExistingTable) { this.dataStoreId = dataStoreId; this.deleteExistingTable = deleteExistingTable; } private void initialize() { try { if (hTable == null) { hTable = HBaseUtil.getHBaseTable(dataStoreId, deleteExistingTable); } } catch (Exception e) { Throwables.propagate(e); } } @Override public byte[] ceiling(byte[] key) { initialize(); try { ResultScanner scanner = hTable.getScanner(new Scan(key)); Result result = scanner.next(); if (result == null || result.isEmpty()) { return null; } else { return result.getRow(); } } catch (IOException e) { Throwables.propagate(e); return null; } } @Override public byte[] floor(byte[] key) { initialize(); Result result; try { result = hTable.getRowOrBefore(key, colFamily); if (result == null || result.isEmpty()) { return null; } else { return result.getRow(); } } catch (IOException e) { Throwables.propagate(e); return null; } } @Override public InputStream openInputStream(byte[] key) { initialize(); Result result = null; try { result = hTable.get(new Get(key)); } catch (IOException e) { Throwables.propagate(e); } byte[] value = result.getValue(colFamily, col); if (value == null || result.isEmpty()) { return null; } else { return new ByteArrayInputStream(value); } } @Override public OutputStream openOutputStream(final byte[] key) { initialize(); return new ByteArrayOutputStream() { @Override public void close() throws IOException { super.close(); Put put = new Put(key); put.add(colFamily, col, toByteArray()); hTable.put(put); } }; } @Override public boolean check(byte[] key) { initialize(); try { return !hTable.exists(new Get(key)); } catch (IOException e) { Throwables.propagate(e); return false; } } @Override public boolean checkAndCreate(byte[] key) { initialize(); // this feature is not yet working // RowLock lockRow = null; // try { // lockRow = hTable.lockRow(key); // } catch (IOException e) { // Throwables.propagate(e); // } // if (lockRow != null) { try { Result result = hTable.get(new Get(key)); if (result.isEmpty()) { Put put = new Put(key); put.add(colFamily, col, new byte[] {}); hTable.put(put); return true; } else { return false; } } catch (Exception e) { Throwables.propagate(e); } finally { // try { // hTable.unlockRow(lockRow); // } catch (IOException e) { // Throwables.propagate(e); // } } // } else { // return false; // } return false; } @Override public void delete(byte[] bytes) { initialize(); try { hTable.delete(new Delete(bytes)); } catch (IOException e) { Throwables.propagate(e); } } @Override public void drop() { HBaseUtil.dropTable(dataStoreId); } @Override public void close() { try { hTable.close(); hTable = null; } catch (IOException e) { Throwables.propagate(e); } } @Override public void flush() { } private class Cursor implements ICursor { final ResultScanner scanner; final Iterator<Result> iterator; byte[] currentValue = null; public Cursor(ResultScanner scanner) { super(); this.scanner = scanner; this.iterator = scanner.iterator(); this.currentValue = null; } @Override public boolean hasNext() { return iterator.hasNext(); } @Override public byte[] next() { try { Result next = iterator.next(); currentValue = next.getValue(colFamily, col); return next.getRow(); } catch (Exception e) { EmfFragActivator.instance.warning("Scanner throws exception", e); return null; } } @Override public InputStream openNextInputStream() { if (currentValue == null) { return null; } else { return new ByteArrayInputStream(currentValue); } } @Override public void close() { scanner.close(); } } @Override public ICursor cursor(byte[] key) { initialize(); ResultScanner scanner = null; try { Scan scan = new Scan(key); scan.setCaching(scanCacheSize); scanner = hTable.getScanner(scan); } catch (IOException e) { Throwables.propagate(e); } return new Cursor(scanner); } @Override public boolean bulkInsert(Map<byte[], byte[]> map) { initialize(); List<Put> puts = new ArrayList<Put>(); for (Entry<byte[], byte[]> entry: map.entrySet()) { Put put = new Put(entry.getKey()); put.add(colFamily, col, entry.getValue()); puts.add(put); } try { hTable.put(puts); } catch (IOException e) { e.printStackTrace(); } return true; } public void setScanCacheSize(int scanCacheSize) { this.scanCacheSize = scanCacheSize; } }