// 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.impala.util;

import java.io.IOException;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class CompressionUtil {

  private final static Logger LOG = LoggerFactory.getLogger(CompressionUtil.class);

  /**
   * Compresses a given input byte array using DeflaterOutputStream. Returns null if
   * the input is null or if there is an error compressing the input.
   */
  public static byte[] deflateCompress(byte[] input) {
    if (input == null) return null;
    ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);
    // TODO: Benchmark other compression levels.
    DeflaterOutputStream stream =
        new DeflaterOutputStream(bos, new Deflater(Deflater.BEST_COMPRESSION));
    try {
      stream.write(input);
      stream.close();
    } catch (IOException e) {
      LOG.error("Error compressing input bytes.", e);
      return null;
    }
    return bos.toByteArray();
  }

  /**
   * Decompresses a deflate-compressed byte array and returns the output bytes. Returns
   * null if the input is null or if there is an error decompressing the input.
   */
  public static byte[] deflateDecompress(byte[] input) {
    if (input == null) return null;
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try{
      IOUtils.copy(new InflaterInputStream(new ByteArrayInputStream(input)), out);
    } catch(IOException e){
      LOG.error("Error decompressing input bytes.", e);
      return null;
    }
    return out.toByteArray();
  }
}

// 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.impala.util;

import java.io.IOException;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class CompressionUtil {

  private final static Logger LOG = LoggerFactory.getLogger(CompressionUtil.class);

  /**
   * Compresses a given input byte array using DeflaterOutputStream. Returns null if
   * the input is null or if there is an error compressing the input.
   */
  public static byte[] deflateCompress(byte[] input) {
    if (input == null) return null;
    ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);
    // Experiments on a wide partitioned table with incremental stats showed that the
    // Deflater with 'BEST_SPEED' level provided reasonable compression ratios at much
    // faster speeds compared to other modes like BEST_COMPRESSION/DEFAULT_COMPRESSION.
    DeflaterOutputStream stream =
        new DeflaterOutputStream(bos, new Deflater(Deflater.BEST_SPEED));
    try {
      stream.write(input);
      stream.close();
    } catch (IOException e) {
      LOG.error("Error compressing input bytes.", e);
      return null;
    }
    return bos.toByteArray();
  }

  /**
   * Decompresses a deflate-compressed byte array and returns the output bytes. Returns
   * null if the input is null or if there is an error decompressing the input.
   */
  public static byte[] deflateDecompress(byte[] input) {
    if (input == null) return null;
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try{
      IOUtils.copy(new InflaterInputStream(new ByteArrayInputStream(input)), out);
    } catch(IOException e){
      LOG.error("Error decompressing input bytes.", e);
      return null;
    }
    return out.toByteArray();
  }
}

Switch to faster deflater compression level for incr stats