blob: 4581962e6de242b0432d27abc85cf600275dd2be [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.carbondata.core.localdictionary.dictionaryholder;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.carbondata.core.cache.dictionary.DictionaryByteArrayWrapper;
import org.apache.carbondata.core.constants.CarbonCommonConstants;
import org.apache.carbondata.core.localdictionary.exception.DictionaryThresholdReachedException;
import org.apache.carbondata.core.util.CarbonProperties;
/**
* Map based dictionary holder class, it will use map to hold
* the dictionary key and its value
*/
public class MapBasedDictionaryStore implements DictionaryStore {
/**
* use to assign dictionary value to new key
*/
private int lastAssignValue;
/**
* to maintain dictionary key value
*/
private final Map<DictionaryByteArrayWrapper, Integer> dictionary;
/**
* maintaining array for reverse lookup
* otherwise iterating every time in map for reverse lookup will be slowdown the performance
* It will only maintain the reference
*/
private DictionaryByteArrayWrapper[] referenceDictionaryArray;
/**
* dictionary threshold to check if threshold is reached
*/
private int dictionaryThreshold;
/**
* dictionary threshold size in bytes
*/
private long dictionarySizeThresholdInBytes;
/**
* for checking threshold is reached or not
*/
private boolean isThresholdReached;
/**
* current data size
*/
private long currentSize;
public MapBasedDictionaryStore(int dictionaryThreshold) {
this.dictionaryThreshold = dictionaryThreshold;
this.dictionarySizeThresholdInBytes = Integer.parseInt(CarbonProperties.getInstance()
.getProperty(CarbonCommonConstants.CARBON_LOCAL_DICTIONARY_SIZE_THRESHOLD_IN_MB)) << 20;
this.dictionary = new ConcurrentHashMap<>();
this.referenceDictionaryArray = new DictionaryByteArrayWrapper[dictionaryThreshold];
}
/**
* Below method will be used to add dictionary value to dictionary holder
* if it is already present in the holder then it will return exiting dictionary value.
*
* @param data dictionary key
* @return dictionary value
*/
@Override
public int putIfAbsent(byte[] data) throws DictionaryThresholdReachedException {
// check if threshold has already reached
checkIfThresholdReached();
DictionaryByteArrayWrapper key = new DictionaryByteArrayWrapper(data);
// get the dictionary value
Integer value = dictionary.get(key);
// if value is null then dictionary is not present in store
if (null == value) {
// acquire the lock
synchronized (dictionary) {
// check threshold
checkIfThresholdReached();
// get the value again as other thread might have added
value = dictionary.get(key);
// double checking
if (null == value) {
// increment the value
value = ++lastAssignValue;
currentSize += data.length;
// if new value is greater than threshold
if (value > dictionaryThreshold || currentSize > dictionarySizeThresholdInBytes) {
// set the threshold boolean to true
isThresholdReached = true;
// throw exception
checkIfThresholdReached();
}
// add to reference array
// position is -1 as dictionary value starts from 1
this.referenceDictionaryArray[value - 1] = key;
dictionary.put(key, value);
}
}
}
return value;
}
private void checkIfThresholdReached() throws DictionaryThresholdReachedException {
if (isThresholdReached) {
if (currentSize > dictionarySizeThresholdInBytes) {
throw new DictionaryThresholdReachedException(
"Unable to generate dictionary. Dictionary Size crossed bytes: "
+ dictionarySizeThresholdInBytes);
} else {
throw new DictionaryThresholdReachedException(
"Unable to generate dictionary value. Dictionary threshold reached");
}
}
}
/**
* Below method to get the current size of dictionary
*
* @return
*/
@Override
public boolean isThresholdReached() {
return isThresholdReached;
}
/**
* Below method will be used to get the dictionary key based on value
*
* @param value dictionary value
* Caller will take of passing proper value
* @return dictionary key based on value
*/
@Override
public byte[] getDictionaryKeyBasedOnValue(int value) {
assert referenceDictionaryArray != null;
// reference array index will be -1 of the value as dictionary value starts from 1
return referenceDictionaryArray[value - 1].getData();
}
}