/*
* Copyright 2010 Outerthought bvba
*
* 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.
*/
package org.lilyproject.repository.impl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import org.apache.commons.codec.binary.Hex;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HTableInterface;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.util.Bytes;
import org.lilyproject.repository.api.Blob;
import org.lilyproject.repository.api.BlobException;
import org.lilyproject.repository.api.BlobStoreAccess;
import org.lilyproject.util.hbase.HBaseTableFactory;
import org.lilyproject.util.hbase.HBaseTableFactoryImpl;
public class HBaseBlobStoreAccess implements BlobStoreAccess {
private static final byte[] BLOB_TABLE = Bytes.toBytes("blob");
private static final String ID = "HBASE";
private static final String BLOBS_COLUMN_FAMILY = "data";
private static final byte[] BLOBS_COLUMN_FAMILY_BYTES = Bytes.toBytes(BLOBS_COLUMN_FAMILY);
private static final byte[] BLOB_COLUMN = Bytes.toBytes("b");
private boolean clientMode = false;
private HTableInterface table;
public HBaseBlobStoreAccess(Configuration hbaseConf) throws IOException, InterruptedException {
this(hbaseConf, false);
}
public HBaseBlobStoreAccess(Configuration hbaseConf, boolean clientMode) throws IOException, InterruptedException {
this(new HBaseTableFactoryImpl(hbaseConf), clientMode);
}
public HBaseBlobStoreAccess(HBaseTableFactory tableFactory) throws IOException, InterruptedException {
this(tableFactory, false);
}
public HBaseBlobStoreAccess(HBaseTableFactory tableFactory, boolean clientMode) throws IOException, InterruptedException {
HTableDescriptor tableDescriptor = new HTableDescriptor(BLOB_TABLE);
tableDescriptor.addFamily(new HColumnDescriptor(BLOBS_COLUMN_FAMILY));
table = tableFactory.getTable(tableDescriptor, !clientMode);
}
@Override
public String getId() {
return ID;
}
@Override
public OutputStream getOutputStream(Blob blob) throws BlobException {
UUID uuid = UUID.randomUUID();
byte[] blobKey = Bytes.toBytes(uuid.getMostSignificantBits());
blobKey = Bytes.add(blobKey, Bytes.toBytes(uuid.getLeastSignificantBits()));
return new HBaseBlobOutputStream(table, blobKey, blob);
}
@Override
public InputStream getInputStream(byte[] blobKey) throws BlobException {
Get get = new Get(blobKey);
get.addColumn(BLOBS_COLUMN_FAMILY_BYTES, BLOB_COLUMN);
Result result;
try {
result = table.get(get);
} catch (IOException e) {
throw new BlobException("Failed to open an inputstream for blobkey '" + Hex.encodeHexString(blobKey) + "' on the HBASE blobstore", e);
}
byte[] value = result.getValue(BLOBS_COLUMN_FAMILY_BYTES, BLOB_COLUMN);
if (value == null) {
throw new BlobException("Failed to open an inputstream for blobkey '" + Hex.encodeHexString(blobKey) + "' since no blob was found on the HBASE blobstore");
}
return new ByteArrayInputStream(value);
}
@Override
public void delete(byte[] blobKey) throws BlobException {
Delete delete = new Delete(blobKey);
try {
table.delete(delete);
} catch (IOException e) {
throw new BlobException("Failed to delete blob with key '" + Hex.encodeHexString(blobKey) + "' from the DFS blobstore", e);
}
}
@Override
public boolean incubate() {
return true;
}
private class HBaseBlobOutputStream extends ByteArrayOutputStream {
private final HTableInterface blobTable;
private final byte[] blobKey;
private final Blob blob;
HBaseBlobOutputStream(HTableInterface table, byte[] blobKey, Blob blob) {
super();
blobTable = table;
this.blobKey = blobKey;
this.blob = blob;
}
@Override
public void close() throws IOException {
super.close();
byte[] bytes = toByteArray();
Put put = new Put(blobKey);
put.add(BLOBS_COLUMN_FAMILY_BYTES, BLOB_COLUMN, bytes);
blobTable.put(put);
blob.setValue(blobKey);
}
}
}