blob: 5154cc4bbb1300a0a228a83216249ee64ddea484 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.eagle.log.entity;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.eagle.log.entity.meta.EntityConstants;
import org.apache.eagle.log.entity.meta.EntityDefinition;
import org.apache.eagle.common.ByteUtil;
public class RowkeyBuilder {
public static final int EMPTY_PARTITION_DEFAULT_HASH_CODE = 0;
/**
* Generate the internal sorted hashmap for tags. Please note the partition tags should not be included in the result map.
* @param partitions array of partition tags in order
* @param tags tags of the entity
* @return the sorted hash map of the tags
*/
public static SortedMap<Integer, Integer> generateSortedTagMap(String[] partitions, Map<String, String> tags) {
final SortedMap<Integer, Integer> tagHashMap = new TreeMap<Integer, Integer>();
for (Map.Entry<String, String> entry: tags.entrySet()) {
final String tagName = entry.getKey();
final String tagValue = entry.getValue();
// If it's a partition tag, we need to remove it from tag hash list. It need to
// put to the fix partition hash slot in rowkey.
if (tagValue == null || isPartitionTag(partitions, tagName))
continue;
tagHashMap.put(tagName.hashCode(), tagValue.hashCode());
}
return tagHashMap;
}
/**
* build rowkey from InternalLog object
* @param log internal log entity to write
* @return the rowkey of the entity
*/
public static byte[] buildRowkey(InternalLog log) {
final String[] partitions = log.getPartitions();
final Map<String, String> tags = log.getTags();
final SortedMap<Integer, Integer> tagHashMap = generateSortedTagMap(partitions, tags);
// reverse timestamp
long ts = Long.MAX_VALUE - log.getTimestamp();
List<Integer> partitionHashValues = new ArrayList<Integer>();
if (partitions != null) {
for (String partition : partitions) {
final String tagValue = tags.get(partition);
if (tagValue != null) {
partitionHashValues.add(tagValue.hashCode());
} else {
partitionHashValues.add(EMPTY_PARTITION_DEFAULT_HASH_CODE);
}
}
}
return buildRowkey(log.getPrefix().hashCode(), partitionHashValues, ts, tagHashMap);
}
public static long getTimestamp(byte[] rowkey, EntityDefinition ed) {
if (!ed.isTimeSeries()) {
return EntityConstants.FIXED_WRITE_TIMESTAMP;
}
final int offset = (ed.getPartitions() == null) ? 4 : (4 + ed.getPartitions().length * 4);
return Long.MAX_VALUE - ByteUtil.bytesToLong(rowkey, offset);
}
/**
* Check if the tagName is one of the partition tags
* @param partitions paritition tags of the entity
* @param tagName the tag name that needs to check
* @return
*/
private static boolean isPartitionTag(String[] partitions, String tagName) {
if (partitions != null) {
for (String partition : partitions) {
if (partition.equals(tagName)) {
return true;
}
}
}
return false;
}
/**
* rowkey is: prefixHash:4 + (partitionValueHash:4)* + timestamp:8 + (tagnameHash:4 + tagvalueHash:4)*
* partition fields are sorted by partition definition order, while tag fields are sorted by tag name's
* hash code values.
*/
private static byte[] buildRowkey(int prefixHash, List<Integer> partitionHashValues, long timestamp, SortedMap<Integer, Integer> tags){
// allocate byte array for rowkey
final int len = 4 + 8 + tags.size() * (4 + 4) + (partitionHashValues.size() * 4);
final byte[] rowkey = new byte[len];
int offset = 0;
// 1. set prefix
ByteUtil.intToBytes(prefixHash, rowkey, offset);
offset += 4;
// 2. set partition
for (Integer partHash : partitionHashValues) {
ByteUtil.intToBytes(partHash, rowkey, offset);
offset += 4;
}
// 3. set timestamp
ByteUtil.longToBytes(timestamp, rowkey, offset);
offset += 8;
// 4. set tag key/value hashes
for (Map.Entry<Integer, Integer> entry : tags.entrySet()) {
ByteUtil.intToBytes(entry.getKey(), rowkey, offset);
offset += 4;
ByteUtil.intToBytes(entry.getValue(), rowkey, offset);
offset += 4;
}
return rowkey;
}
}