/**
* 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.deephacks.confit.internal.hbase;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import org.apache.hadoop.hbase.KeyValue;
import org.deephacks.confit.model.BeanId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.deephacks.confit.internal.hbase.HBeanRow.PRED_COLUMN_FAMILY;
public class HBeanPredecessors {
private final Map<Short, byte[]> predecessors = new HashMap<>();
public HBeanPredecessors() {
}
public HBeanPredecessors(KeyValue kv) {
if (!Arrays.equals(kv.getFamily(), HBeanRow.PRED_COLUMN_FAMILY)) {
throw new IllegalArgumentException("KeyValue is not a predecessor column family");
}
short sid = Bytes.getShort(kv.getQualifier());
predecessors.put(sid, kv.getValue());
}
public List<KeyValue> getKeyValue(byte[] rowkey) {
ArrayList<KeyValue> kvs = new ArrayList<>();
for (short sid : predecessors.keySet()) {
byte[] sidBytes = Bytes.fromShort(sid);
kvs.add(new KeyValue(rowkey, HBeanRow.PRED_COLUMN_FAMILY, sidBytes, predecessors
.get(sid)));
}
return kvs;
}
public List<BeanId> getBeanId(byte[] rowkey, UniqueIds uids) {
List<KeyValue> kvs = getKeyValue(rowkey);
List<BeanId> result = new ArrayList<>();
for (int i = 0; i < kvs.size(); i++) {
byte[] sid = kvs.get(i).getQualifier();
byte[][] ids = getIds(kvs.get(i));
for (byte[] id : ids) {
byte[] key = new byte[6];
System.arraycopy(sid, 0, key, 0, 2);
System.arraycopy(id, 0, key, 2, 4);
result.add(HBeanRow.getBeanId(key, uids));
}
}
return result;
}
public static Multimap<byte[], byte[]> getPredecessors(Multimap<String, String> predecessors,
final UniqueIds uids) {
final Multimap<byte[], byte[]> bytes = ArrayListMultimap.create();
for (String schemaName : predecessors.keySet()) {
final byte[] sid = uids.getUsid().getId(schemaName);
Collection<String> ids = predecessors.get(schemaName);
bytes.put(sid, HBeanReferences.getIids(new ArrayList<String>(ids), uids));
}
return bytes;
}
/**
* If this key value is of predecessor familiy type.
*/
public static boolean isPredecessor(KeyValue kv) {
if (Bytes.equals(kv.getFamily(), PRED_COLUMN_FAMILY)) {
return true;
}
return false;
}
public void addRow(HBeanRow row) {
addId(row.getSid(), row.getUid());
}
public void addKeyValue(KeyValue kv) {
byte[][] ids = getIds(kv);
for (byte[] id : ids) {
addId(kv.getQualifier(), id);
}
}
public void addId(byte[] sid, byte[] id) {
validateInput(sid, id);
short shortId = Bytes.getShort(sid);
byte[] ids = predecessors.get(shortId);
if (ids == null) {
ids = new byte[0];
}
ids = BytesUtils.add(ids, Bytes.getInt(id));
predecessors.put(shortId, ids);
}
public void removeKeyValue(KeyValue kv) {
byte[][] ids = getIds(kv);
for (byte[] id : ids) {
removeId(kv.getQualifier(), id);
}
}
public void removeRow(HBeanRow row) {
removeId(row.getSid(), row.getUid());
}
private byte[][] getIds(KeyValue kv) {
byte[] bytes = kv.getValue();
int num = bytes.length / 4;
byte[][] ids = new byte[num][];
for (int i = 0; i < num; i++) {
int idx = i * 4;
ids[i] = new byte[] { bytes[idx + 0], bytes[idx + 1], bytes[idx + 2], bytes[idx + 3] };
}
return ids;
}
public void removeId(byte[] sid, byte[] id) {
validateInput(sid, id);
short shortId = Bytes.getShort(sid);
byte[] ids = predecessors.get(shortId);
ids = BytesUtils.remove(ids, Bytes.getInt(id));
predecessors.put(shortId, ids);
}
private void validateInput(byte[] sid, byte[] id) {
if (sid.length != 2) {
throw new IllegalArgumentException("sid must be 2 bytes.");
}
if (id.length != 4) {
throw new IllegalArgumentException("Ids must be 4 bytes.");
}
}
}