Skip to content

Commit c391ad6

Browse files
committed
DRILL-8259: Supports advanced HBase persistence storage options
1 parent b64acdd commit c391ad6

15 files changed

+307
-109
lines changed

common/src/test/java/org/apache/drill/categories/HbaseStorageTest.java renamed to common/src/test/java/org/apache/drill/categories/HBaseStorageTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@
2020
/**
2121
* This is a category used to mark unit tests that test the HBase storage plugin.
2222
*/
23-
public interface HbaseStorageTest {
23+
public interface HBaseStorageTest {
2424
}

contrib/storage-hbase/src/main/java/org/apache/drill/exec/store/hbase/DrillHBaseConstants.java

+5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.drill.common.types.Types;
2424

2525
public interface DrillHBaseConstants {
26+
2627
String ROW_KEY = "row_key";
2728

2829
SchemaPath ROW_KEY_PATH = SchemaPath.getSimplePath(ROW_KEY);
@@ -38,4 +39,8 @@ public interface DrillHBaseConstants {
3839
String SYS_STORE_PROVIDER_HBASE_TABLE = "drill.exec.sys.store.provider.hbase.table";
3940

4041
String SYS_STORE_PROVIDER_HBASE_CONFIG = "drill.exec.sys.store.provider.hbase.config";
42+
43+
String SYS_STORE_PROVIDER_HBASE_TABLE_CONFIG = "drill.exec.sys.store.provider.hbase.table_config";
44+
45+
String SYS_STORE_PROVIDER_HBASE_COLUMN_CONFIG = "drill.exec.sys.store.provider.hbase.column_config";
4146
}

contrib/storage-hbase/src/main/java/org/apache/drill/exec/store/hbase/config/HBasePersistentStore.java

+10-10
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
*/
1818
package org.apache.drill.exec.store.hbase.config;
1919

20-
import static org.apache.drill.exec.store.hbase.config.HBasePersistentStoreProvider.FAMILY;
21-
import static org.apache.drill.exec.store.hbase.config.HBasePersistentStoreProvider.QUALIFIER;
20+
import static org.apache.drill.exec.store.hbase.config.HBasePersistentStoreProvider.FAMILY_NAME;
21+
import static org.apache.drill.exec.store.hbase.config.HBasePersistentStoreProvider.QUALIFIER_NAME;
2222

2323
import java.io.IOException;
2424
import java.util.Iterator;
@@ -70,7 +70,7 @@ public PersistentStoreMode getMode() {
7070
public boolean contains(String key) {
7171
try {
7272
Get get = new Get(row(key));
73-
get.addColumn(FAMILY, QUALIFIER);
73+
get.addColumn(FAMILY_NAME, QUALIFIER_NAME);
7474
return hbaseTable.exists(get);
7575
} catch (IOException e) {
7676
throw UserException
@@ -82,13 +82,13 @@ public boolean contains(String key) {
8282

8383
@Override
8484
public V get(String key) {
85-
return get(key, FAMILY);
85+
return get(key, FAMILY_NAME);
8686
}
8787

8888
protected synchronized V get(String key, byte[] family) {
8989
try {
9090
Get get = new Get(row(key));
91-
get.addColumn(family, QUALIFIER);
91+
get.addColumn(family, QUALIFIER_NAME);
9292
Result r = hbaseTable.get(get);
9393
if(r.isEmpty()){
9494
return null;
@@ -103,13 +103,13 @@ protected synchronized V get(String key, byte[] family) {
103103

104104
@Override
105105
public void put(String key, V value) {
106-
put(key, FAMILY, value);
106+
put(key, FAMILY_NAME, value);
107107
}
108108

109109
protected synchronized void put(String key, byte[] family, V value) {
110110
try {
111111
Put put = new Put(row(key));
112-
put.addColumn(family, QUALIFIER, bytes(value));
112+
put.addColumn(family, QUALIFIER_NAME, bytes(value));
113113
hbaseTable.put(put);
114114
} catch (IOException e) {
115115
throw UserException.dataReadError(e)
@@ -122,8 +122,8 @@ protected synchronized void put(String key, byte[] family, V value) {
122122
public synchronized boolean putIfAbsent(String key, V value) {
123123
try {
124124
Put put = new Put(row(key));
125-
put.addColumn(FAMILY, QUALIFIER, bytes(value));
126-
return hbaseTable.checkAndPut(put.getRow(), FAMILY, QUALIFIER, null /*absent*/, put);
125+
put.addColumn(FAMILY_NAME, QUALIFIER_NAME, bytes(value));
126+
return hbaseTable.checkAndPut(put.getRow(), FAMILY_NAME, QUALIFIER_NAME, null /*absent*/, put);
127127
} catch (IOException e) {
128128
throw UserException.dataReadError(e)
129129
.message("Caught error while putting row '%s' into table '%s'", key, hbaseTableName)
@@ -183,7 +183,7 @@ private class Iter implements Iterator<Entry<String, V>> {
183183
Iter(int take) {
184184
try {
185185
Scan scan = new Scan(tableNameStartKey, tableNameStopKey);
186-
scan.addColumn(FAMILY, QUALIFIER);
186+
scan.addColumn(FAMILY_NAME, QUALIFIER_NAME);
187187
scan.setCaching(Math.min(take, 100));
188188
scan.setBatch(take); // set batch size
189189
scanner = hbaseTable.getScanner(scan);

contrib/storage-hbase/src/main/java/org/apache/drill/exec/store/hbase/config/HBasePersistentStoreProvider.java

+160-43
Original file line numberDiff line numberDiff line change
@@ -20,116 +20,233 @@
2020
import java.io.IOException;
2121
import java.util.Map;
2222

23+
import org.apache.drill.common.AutoCloseables;
2324
import org.apache.drill.common.exceptions.DrillRuntimeException;
2425
import org.apache.drill.exec.exception.StoreException;
2526
import org.apache.drill.exec.store.hbase.DrillHBaseConstants;
2627
import org.apache.drill.exec.store.sys.PersistentStore;
2728
import org.apache.drill.exec.store.sys.PersistentStoreConfig;
2829
import org.apache.drill.exec.store.sys.PersistentStoreRegistry;
2930
import org.apache.drill.exec.store.sys.store.provider.BasePersistentStoreProvider;
31+
import org.apache.drill.shaded.guava.com.google.common.annotations.VisibleForTesting;
32+
import org.apache.drill.shaded.guava.com.google.common.collect.Maps;
3033
import org.apache.hadoop.conf.Configuration;
3134
import org.apache.hadoop.hbase.HBaseConfiguration;
32-
import org.apache.hadoop.hbase.HColumnDescriptor;
3335
import org.apache.hadoop.hbase.HConstants;
34-
import org.apache.hadoop.hbase.HTableDescriptor;
3536
import org.apache.hadoop.hbase.TableName;
3637
import org.apache.hadoop.hbase.client.Admin;
38+
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
3739
import org.apache.hadoop.hbase.client.Connection;
3840
import org.apache.hadoop.hbase.client.ConnectionFactory;
41+
import org.apache.hadoop.hbase.client.Durability;
3942
import org.apache.hadoop.hbase.client.Table;
43+
import org.apache.hadoop.hbase.client.TableDescriptor;
44+
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
45+
import org.apache.hadoop.hbase.io.compress.Compression.Algorithm;
46+
import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
4047
import org.apache.hadoop.hbase.util.Bytes;
4148

42-
import org.apache.drill.shaded.guava.com.google.common.annotations.VisibleForTesting;
43-
4449
public class HBasePersistentStoreProvider extends BasePersistentStoreProvider {
4550
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(HBasePersistentStoreProvider.class);
4651

47-
static final byte[] FAMILY = Bytes.toBytes("s");
52+
public static final byte[] FAMILY_NAME = Bytes.toBytes("s");
53+
54+
public static final byte[] QUALIFIER_NAME = Bytes.toBytes("d");
4855

49-
static final byte[] QUALIFIER = Bytes.toBytes("d");
56+
private static final String HBASE_CLIENT_ID = "drill-hbase-persistent-store-client";
5057

5158
private final TableName hbaseTableName;
5259

60+
private Table hbaseTable;
61+
5362
private Configuration hbaseConf;
5463

55-
private Connection connection;
64+
private final Map<String, Object> tableConfig;
5665

57-
private Table hbaseTable;
66+
private final Map<String, Object> columnConfig;
5867

68+
private Connection connection;
69+
70+
@SuppressWarnings("unchecked")
5971
public HBasePersistentStoreProvider(PersistentStoreRegistry registry) {
60-
@SuppressWarnings("unchecked")
61-
final Map<String, Object> config = (Map<String, Object>) registry.getConfig().getAnyRef(DrillHBaseConstants.SYS_STORE_PROVIDER_HBASE_CONFIG);
62-
this.hbaseConf = HBaseConfiguration.create();
63-
this.hbaseConf.set(HConstants.HBASE_CLIENT_INSTANCE_ID, "drill-hbase-persistent-store-client");
64-
if (config != null) {
65-
for (Map.Entry<String, Object> entry : config.entrySet()) {
66-
this.hbaseConf.set(entry.getKey(), String.valueOf(entry.getValue()));
72+
final Map<String, Object> hbaseConfig = (Map<String, Object>) registry.getConfig().getAnyRef(DrillHBaseConstants.SYS_STORE_PROVIDER_HBASE_CONFIG);
73+
if (registry.getConfig().hasPath(DrillHBaseConstants.SYS_STORE_PROVIDER_HBASE_TABLE_CONFIG)) {
74+
tableConfig = (Map<String, Object>) registry.getConfig().getAnyRef(DrillHBaseConstants.SYS_STORE_PROVIDER_HBASE_TABLE_CONFIG);
75+
} else {
76+
tableConfig = Maps.newHashMap();
77+
}
78+
if (registry.getConfig().hasPath(DrillHBaseConstants.SYS_STORE_PROVIDER_HBASE_COLUMN_CONFIG)) {
79+
columnConfig = (Map<String, Object>) registry.getConfig().getAnyRef(DrillHBaseConstants.SYS_STORE_PROVIDER_HBASE_COLUMN_CONFIG);
80+
} else {
81+
columnConfig = Maps.newHashMap();
82+
}
83+
hbaseConf = HBaseConfiguration.create();
84+
hbaseConf.set(HConstants.HBASE_CLIENT_INSTANCE_ID, HBASE_CLIENT_ID);
85+
if (hbaseConfig != null) {
86+
for (Map.Entry<String, Object> entry : hbaseConfig.entrySet()) {
87+
hbaseConf.set(entry.getKey(), String.valueOf(entry.getValue()));
6788
}
6889
}
69-
this.hbaseTableName = TableName.valueOf(registry.getConfig().getString(DrillHBaseConstants.SYS_STORE_PROVIDER_HBASE_TABLE));
90+
logger.info("Received the hbase config is {}", hbaseConfig);
91+
if (!tableConfig.isEmpty()) {
92+
logger.info("Received the table config is {}", tableConfig);
93+
}
94+
if (!columnConfig.isEmpty()) {
95+
logger.info("Received the column config is {}", columnConfig);
96+
}
97+
hbaseTableName = TableName.valueOf(registry.getConfig().getString(DrillHBaseConstants.SYS_STORE_PROVIDER_HBASE_TABLE));
7098
}
7199

72100
@VisibleForTesting
73101
public HBasePersistentStoreProvider(Configuration conf, String storeTableName) {
102+
this.tableConfig = Maps.newHashMap();
103+
this.columnConfig = Maps.newHashMap();
74104
this.hbaseConf = conf;
75105
this.hbaseTableName = TableName.valueOf(storeTableName);
76106
}
77107

78-
108+
@VisibleForTesting
109+
public HBasePersistentStoreProvider(Map<String, Object> tableConfig, Map<String, Object> columnConfig, Configuration conf, String storeTableName) {
110+
this.tableConfig = tableConfig;
111+
this.columnConfig = columnConfig;
112+
this.hbaseConf = conf;
113+
this.hbaseTableName = TableName.valueOf(storeTableName);
114+
}
79115

80116
@Override
81117
public <V> PersistentStore<V> getOrCreateStore(PersistentStoreConfig<V> config) throws StoreException {
82-
switch(config.getMode()){
118+
switch (config.getMode()) {
83119
case BLOB_PERSISTENT:
84120
case PERSISTENT:
85-
return new HBasePersistentStore<>(config, this.hbaseTable);
86-
121+
return new HBasePersistentStore<>(config, hbaseTable);
87122
default:
88-
throw new IllegalStateException();
123+
throw new IllegalStateException("Unknown persistent mode");
89124
}
90125
}
91126

92-
93127
@Override
94128
public void start() throws IOException {
129+
// Create the column family builder
130+
ColumnFamilyDescriptorBuilder columnFamilyBuilder = ColumnFamilyDescriptorBuilder
131+
.newBuilder(FAMILY_NAME)
132+
.setMaxVersions(1);
133+
// Append the config to column family
134+
verifyAndSetColumnConfig(columnConfig, columnFamilyBuilder);
135+
// Create the table builder
136+
TableDescriptorBuilder tableBuilder = TableDescriptorBuilder
137+
.newBuilder(hbaseTableName)
138+
.setColumnFamily(columnFamilyBuilder.build());
139+
// Append the config to table
140+
verifyAndSetTableConfig(tableConfig, tableBuilder);
95141
this.connection = ConnectionFactory.createConnection(hbaseConf);
96-
97142
try(Admin admin = connection.getAdmin()) {
98143
if (!admin.tableExists(hbaseTableName)) {
99-
HTableDescriptor desc = new HTableDescriptor(hbaseTableName);
100-
desc.addFamily(new HColumnDescriptor(FAMILY).setMaxVersions(1));
101-
admin.createTable(desc);
144+
// Go to create the table
145+
admin.createTable(tableBuilder.build());
146+
logger.info("The HBase table of persistent store created : {}", hbaseTableName);
102147
} else {
103-
HTableDescriptor desc = admin.getTableDescriptor(hbaseTableName);
104-
if (!desc.hasFamily(FAMILY)) {
148+
TableDescriptor table = admin.getDescriptor(hbaseTableName);
149+
if (!admin.isTableEnabled(hbaseTableName)) {
150+
admin.enableTable(hbaseTableName); // In case the table is disabled
151+
}
152+
if (!table.hasColumnFamily(FAMILY_NAME)) {
105153
throw new DrillRuntimeException("The HBase table " + hbaseTableName
106154
+ " specified as persistent store exists but does not contain column family: "
107-
+ (Bytes.toString(FAMILY)));
155+
+ (Bytes.toString(FAMILY_NAME)));
108156
}
157+
logger.info("The HBase table of persistent store is loaded : {}", hbaseTableName);
109158
}
110159
}
111160

112161
this.hbaseTable = connection.getTable(hbaseTableName);
113162
}
114163

115-
@Override
116-
public synchronized void close() {
117-
if (this.hbaseTable != null) {
118-
try {
119-
this.hbaseTable.close();
120-
this.hbaseTable = null;
121-
} catch (IOException e) {
122-
logger.warn("Caught exception while closing HBase table.", e);
164+
/**
165+
* Verify the configuration of HBase table and
166+
* add them to the table builder.
167+
* @param config Received the table config
168+
* @param builder HBase table builder
169+
*/
170+
private void verifyAndSetTableConfig(Map<String, Object> config, TableDescriptorBuilder builder) {
171+
for (Map.Entry<String, Object> entry : config.entrySet()) {
172+
switch (entry.getKey().toUpperCase()) {
173+
case TableDescriptorBuilder.DURABILITY:
174+
Durability durability = Durability.valueOf(((String) entry.getValue()).toUpperCase());
175+
builder.setDurability(durability);
176+
break;
177+
case TableDescriptorBuilder.COMPACTION_ENABLED:
178+
builder.setCompactionEnabled((Boolean) entry.getValue());
179+
break;
180+
case TableDescriptorBuilder.SPLIT_ENABLED:
181+
builder.setSplitEnabled((Boolean) entry.getValue());
182+
break;
183+
case TableDescriptorBuilder.FLUSH_POLICY:
184+
builder.setFlushPolicyClassName((String) entry.getValue());
185+
break;
186+
case TableDescriptorBuilder.SPLIT_POLICY:
187+
builder.setRegionSplitPolicyClassName((String) entry.getValue());
188+
break;
189+
case TableDescriptorBuilder.MAX_FILESIZE:
190+
builder.setMaxFileSize((Integer) entry.getValue());
191+
break;
192+
case TableDescriptorBuilder.MEMSTORE_FLUSHSIZE:
193+
builder.setMemStoreFlushSize((Integer) entry.getValue());
194+
break;
195+
default:
196+
break;
123197
}
124198
}
125-
if (this.connection != null && !this.connection.isClosed()) {
126-
try {
127-
this.connection.close();
128-
} catch (IOException e) {
129-
logger.warn("Caught exception while closing HBase connection.", e);
199+
}
200+
201+
/**
202+
* Verify the configuration of HBase column family and
203+
* add them to the column family builder.
204+
* @param config Received the column config
205+
* @param builder HBase column family builder
206+
*/
207+
private void verifyAndSetColumnConfig(Map<String, Object> config, ColumnFamilyDescriptorBuilder builder) {
208+
for (Map.Entry<String, Object> entry : config.entrySet()) {
209+
switch (entry.getKey().toUpperCase()) {
210+
case ColumnFamilyDescriptorBuilder.MAX_VERSIONS:
211+
builder.setMaxVersions((Integer) entry.getValue());
212+
break;
213+
case ColumnFamilyDescriptorBuilder.TTL:
214+
builder.setTimeToLive((Integer) entry.getValue());
215+
break;
216+
case ColumnFamilyDescriptorBuilder.COMPRESSION:
217+
Algorithm algorithm = Algorithm.valueOf(((String) entry.getValue()).toUpperCase());
218+
builder.setCompressionType(algorithm);
219+
break;
220+
case ColumnFamilyDescriptorBuilder.BLOCKCACHE:
221+
builder.setBlockCacheEnabled((Boolean) entry.getValue());
222+
break;
223+
case ColumnFamilyDescriptorBuilder.BLOCKSIZE:
224+
builder.setBlocksize((Integer) entry.getValue());
225+
break;
226+
case ColumnFamilyDescriptorBuilder.DATA_BLOCK_ENCODING:
227+
DataBlockEncoding encoding = DataBlockEncoding.valueOf(((String) entry.getValue()).toUpperCase());
228+
builder.setDataBlockEncoding(encoding);
229+
break;
230+
case ColumnFamilyDescriptorBuilder.IN_MEMORY:
231+
builder.setInMemory((Boolean) entry.getValue());
232+
break;
233+
case ColumnFamilyDescriptorBuilder.DFS_REPLICATION:
234+
builder.setDFSReplication(((Integer) entry.getValue()).shortValue());
235+
break;
236+
default:
237+
break;
130238
}
131-
this.connection = null;
132239
}
133240
}
134241

242+
@Override
243+
public synchronized void close() {
244+
if (hbaseTable != null) {
245+
AutoCloseables.closeSilently(hbaseTable);
246+
}
247+
if (connection != null && !connection.isClosed()) {
248+
AutoCloseables.closeSilently(connection);
249+
}
250+
logger.info("The HBase connection of persistent store closed.");
251+
}
135252
}

contrib/storage-hbase/src/test/java/org/apache/drill/hbase/HBaseRecordReaderTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717
*/
1818
package org.apache.drill.hbase;
1919

20-
import org.apache.drill.categories.HbaseStorageTest;
20+
import org.apache.drill.categories.HBaseStorageTest;
2121
import org.apache.drill.categories.SlowTest;
2222
import org.junit.Test;
2323
import org.junit.experimental.categories.Category;
2424

2525
import static org.apache.drill.test.TestBuilder.mapOf;
2626

27-
@Category({SlowTest.class, HbaseStorageTest.class})
27+
@Category({SlowTest.class, HBaseStorageTest.class})
2828
public class HBaseRecordReaderTest extends BaseHBaseTest {
2929

3030
@Test

contrib/storage-hbase/src/test/java/org/apache/drill/hbase/HBaseTestsSuite.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public class HBaseTestsSuite extends BaseTest {
7676

7777
private static Configuration conf;
7878

79-
private static Connection conn;
79+
protected static Connection conn;
8080
private static Admin admin;
8181

8282
private static HBaseTestingUtility UTIL;

0 commit comments

Comments
 (0)