| /* |
| * 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.datastore.compression; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.apache.carbondata.common.logging.LogServiceFactory; |
| import org.apache.carbondata.core.constants.CarbonCommonConstants; |
| import org.apache.carbondata.core.util.CarbonProperties; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.log4j.Logger; |
| |
| public class CompressorFactory { |
| private static final Logger LOGGER = LogServiceFactory.getLogService( |
| CompressorFactory.class.getName()); |
| private static final CompressorFactory COMPRESSOR_FACTORY = new CompressorFactory(); |
| |
| private final Map<String, Compressor> allSupportedCompressors = new HashMap<>(); |
| |
| public enum NativeSupportedCompressor { |
| SNAPPY("snappy", SnappyCompressor.class), |
| ZSTD("zstd", ZstdCompressor.class), |
| GZIP("gzip", GzipCompressor.class); |
| |
| private String name; |
| private Class<Compressor> compressorClass; |
| private transient Compressor compressor; |
| |
| NativeSupportedCompressor(String name, Class compressorCls) { |
| this.name = name; |
| this.compressorClass = compressorCls; |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| /** |
| * we will load the compressor only if it is needed |
| */ |
| public Compressor getCompressor() { |
| if (this.compressor == null) { |
| try { |
| this.compressor = compressorClass.newInstance(); |
| } catch (InstantiationException | IllegalAccessException e) { |
| throw new RuntimeException("Exception occurs while getting compressor for " + name, e); |
| } |
| } |
| return this.compressor; |
| } |
| } |
| |
| private CompressorFactory() { |
| for (NativeSupportedCompressor nativeSupportedCompressor : NativeSupportedCompressor.values()) { |
| allSupportedCompressors.put(nativeSupportedCompressor.getName(), |
| nativeSupportedCompressor.getCompressor()); |
| } |
| } |
| |
| public static CompressorFactory getInstance() { |
| return COMPRESSOR_FACTORY; |
| } |
| |
| /** |
| * register the compressor using reflection. |
| * If the class name of the compressor has already been registered before, it will return false; |
| * If the reflection fails to work or the compressor name has problem, it will throw |
| * RunTimeException; If it is registered successfully, it will return true. |
| * |
| * @param compressorClassName full class name of the compressor |
| * @return true if register successfully, false if failed. |
| */ |
| private Compressor registerColumnCompressor(String compressorClassName) { |
| if (allSupportedCompressors.containsKey(compressorClassName)) { |
| return allSupportedCompressors.get(compressorClassName); |
| } |
| |
| Class clazz; |
| try { |
| clazz = Class.forName(compressorClassName); |
| Object instance = clazz.newInstance(); |
| if (instance instanceof Compressor) { |
| if (!((Compressor) instance).getName().equals(compressorClassName)) { |
| throw new RuntimeException(String.format("For not carbondata native supported compressor," |
| + " the result of method getName() should be the full class name. Expected '%s'," |
| + " found '%s'", compressorClassName, ((Compressor) instance).getName())); |
| } |
| allSupportedCompressors.put(compressorClassName, (Compressor) instance); |
| LOGGER.info( |
| String.format("sucessfully register compressor %s to carbondata", compressorClassName)); |
| return (Compressor) instance; |
| } else { |
| throw new RuntimeException( |
| String.format("Compressor '%s' should be a subclass of '%s'", |
| compressorClassName, Compressor.class.getCanonicalName())); |
| } |
| } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { |
| LOGGER.error(String.format("Failed to register compressor '%s'", compressorClassName), e); |
| throw new RuntimeException( |
| String.format("Failed to load compressor '%s', currently carbondata supports %s", |
| compressorClassName, StringUtils.join(allSupportedCompressors.keySet(), ", ")), e); |
| } |
| } |
| |
| /** |
| * get the default compressor. |
| * This method can only be called in data load procedure to compress column page. |
| * In query procedure, we should read the compressor information from the metadata |
| * in datafiles when we want to decompress the content. |
| */ |
| public Compressor getCompressor() { |
| String compressorType = CarbonProperties.getInstance() |
| .getProperty(CarbonCommonConstants.COMPRESSOR, CarbonCommonConstants.DEFAULT_COMPRESSOR); |
| return getCompressor(compressorType); |
| } |
| |
| public Compressor getCompressor(String name) { |
| String internalCompressorName = getInternalCompressorName(name); |
| if (null == internalCompressorName) { |
| // maybe this is a new compressor, we will try to register it |
| return registerColumnCompressor(name); |
| } else { |
| return allSupportedCompressors.get(internalCompressorName); |
| } |
| } |
| |
| // if we specify the compressor name in table property, carbondata now will convert the |
| // property value to lowercase, so here we will ingore the case and find the real name. |
| private String getInternalCompressorName(String name) { |
| for (String key : allSupportedCompressors.keySet()) { |
| if (key.equalsIgnoreCase(name)) { |
| return key; |
| } |
| } |
| return null; |
| } |
| } |