/* * Copyright © 2014-2015 Cask Data, Inc. * * 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 co.cask.cdap.data2.dataset2.lib.table.leveldb; import co.cask.cdap.api.common.Bytes; import co.cask.cdap.api.dataset.DataSetException; import co.cask.cdap.api.dataset.DatasetContext; import co.cask.cdap.api.dataset.table.Scanner; import co.cask.cdap.common.conf.CConfiguration; import co.cask.cdap.data2.dataset2.lib.table.FuzzyRowFilter; import co.cask.cdap.data2.dataset2.lib.table.MetricsTable; import co.cask.cdap.data2.dataset2.lib.table.inmemory.PrefixedNamespaces; import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import java.io.IOException; import java.util.Map; import java.util.NavigableMap; import java.util.SortedMap; import javax.annotation.Nullable; /** * A metrics table client based on leveldb. */ public class LevelDBMetricsTable implements MetricsTable { private static final Function<Long, byte[]> LONG_TO_BYTES = new Function<Long, byte[]>() { @Override public byte[] apply(Long input) { return Bytes.toBytes(input); } }; private static final Function<SortedMap<byte[], Long>, SortedMap<byte[], byte[]>> TRANSFORM_MAP_LONG_TO_BYTE_ARRAY = new Function<SortedMap<byte[], Long>, SortedMap<byte[], byte[]>>() { @Override public SortedMap<byte[], byte[]> apply(SortedMap<byte[], Long> input) { return Maps.transformValues(input, LONG_TO_BYTES); } }; private final String tableName; private final LevelDBTableCore core; public LevelDBMetricsTable(DatasetContext datasetContext, String tableName, LevelDBTableService service, CConfiguration cConf) throws IOException { this.core = new LevelDBTableCore(PrefixedNamespaces.namespace(cConf, datasetContext.getNamespaceId(), tableName), service); this.tableName = tableName; } @Override public byte[] get(byte[] row, byte[] column) { try { NavigableMap<byte[], byte[]> result = core.getRow(row, new byte[][]{column}, null, null, -1, null); if (!result.isEmpty()) { return result.get(column); } return null; } catch (IOException e) { throw new DataSetException("Get failed on table " + tableName, e); } } @Override public void put(SortedMap<byte[], ? extends SortedMap<byte[], Long>> updates) { SortedMap<byte[], ? extends SortedMap<byte[], byte[]>> convertedUpdates = Maps.transformValues(updates, TRANSFORM_MAP_LONG_TO_BYTE_ARRAY); try { core.persist(convertedUpdates, System.currentTimeMillis()); } catch (IOException e) { throw new DataSetException("Put failed on table " + tableName, e); } } @Override public synchronized boolean swap(byte[] row, byte[] column, byte[] oldValue, byte[] newValue) { try { return core.swap(row, column, oldValue, newValue); } catch (IOException e) { throw new DataSetException("Swap failed on table " + tableName, e); } } @Override public void increment(byte[] row, Map<byte[], Long> increments) { try { core.increment(row, increments); } catch (IOException e) { throw new DataSetException("Increment failed on table " + tableName, e); } } @Override public void increment(NavigableMap<byte[], NavigableMap<byte[], Long>> updates) { try { core.increment(updates); } catch (IOException e) { throw new DataSetException("Increment failed on table " + tableName, e); } } @Override public long incrementAndGet(byte[] row, byte[] column, long delta) { try { return core.increment(row, ImmutableMap.of(column, delta)).get(column); } catch (IOException e) { throw new DataSetException("IncrementAndGet failed on table " + tableName, e); } } @Override public void delete(byte[] row, byte[][] columns) { try { for (byte[] column : columns) { core.deleteColumn(row, column); } } catch (IOException e) { throw new DataSetException("Delete failed on table " + tableName, e); } } @Override public Scanner scan(@Nullable byte[] start, @Nullable byte[] stop, @Nullable FuzzyRowFilter filter) { try { return core.scan(start, stop, filter, null, null); } catch (IOException e) { throw new DataSetException("Scan failed on table " + tableName, e); } } @Override public void close() throws IOException { // Do nothing } }