/* * 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.cassandra.io.compress; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Collections; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xerial.snappy.Snappy; import org.xerial.snappy.SnappyError; import org.apache.cassandra.utils.JVMStabilityInspector; public class SnappyCompressor implements ICompressor { public static final SnappyCompressor instance = new SnappyCompressor(); private static Logger logger = LoggerFactory.getLogger(SnappyCompressor.class); static { if (!isAvailable()) logger.warn("Cannot initialize native Snappy library. Compression on new sstables will be disabled."); } public static SnappyCompressor create(Map<String, String> compressionOptions) { // this would throw java.lang.NoClassDefFoundError if Snappy class // wasn't found at runtime which should be processed by calling method Snappy.getNativeLibraryVersion(); // no specific options supported so far return instance; } public static boolean isAvailable() { try { create(Collections.<String, String>emptyMap()); return true; } catch (Exception e) { JVMStabilityInspector.inspectThrowable(e); return false; } catch (NoClassDefFoundError | SnappyError | UnsatisfiedLinkError e) { return false; } } public Set<String> supportedOptions() { return Collections.emptySet(); } public int initialCompressedBufferLength(int chunkLength) { return Snappy.maxCompressedLength(chunkLength); } public void compress(ByteBuffer input, ByteBuffer output) throws IOException { int dlimit = output.limit(); Snappy.compress(input, output); // Snappy doesn't match the ICompressor contract w/regards to state it leaves dest ByteBuffer's counters in output.position(output.limit()); output.limit(dlimit); input.position(input.limit()); } public int uncompress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) throws IOException { return Snappy.rawUncompress(input, inputOffset, inputLength, output, outputOffset); } public void uncompress(ByteBuffer input, ByteBuffer output) throws IOException { int dlimit = output.limit(); Snappy.uncompress(input, output); // Snappy doesn't match the ICompressor contract w/regards to state it leaves dest ByteBuffer's counters in output.position(output.limit()); output.limit(dlimit); input.position(input.limit()); } public BufferType preferredBufferType() { return BufferType.OFF_HEAP; } public boolean supports(BufferType bufferType) { // Snappy can't deal with different input and output buffer types. // To avoid possible problems, pretend it can't support array-backed at all. return bufferType == BufferType.OFF_HEAP; } }