Merge branch 'develop'

This commit is contained in:
Taro L. Saito 2015-05-13 11:06:11 +09:00
commit e5d86ee61e
31 changed files with 1204 additions and 613 deletions

View File

@ -56,7 +56,7 @@ $(TARGET)/jni-classes/org/xerial/snappy/SnappyNative.class : $(SRC)/org/xerial/s
$(JAVAC) -source 1.6 -target 1.6 -d $(TARGET)/jni-classes -sourcepath $(SRC) $<
$(SRC)/org/xerial/snappy/SnappyNative.h: $(TARGET)/jni-classes/org/xerial/snappy/SnappyNative.class
$(JAVAH) -force -classpath $(TARGET)/classes -o $@ org.xerial.snappy.SnappyNative
$(JAVAH) -force -classpath $(TARGET)/jni-classes -o $@ org.xerial.snappy.SnappyNative
ifndef USE_GIT
$(SNAPPY_SRC): $(SNAPPY_UNPACKED)
@ -135,6 +135,10 @@ linux-arm:
linux-armhf:
$(MAKE) native CROSS_PREFIX=arm-linux-gnueabihf- OS_NAME=Linux OS_ARCH=armhf
# for cross-compilation on Ubuntu, install the g++-aarch64-linux-gnu
linux-aarch64:
$(MAKE) native CROSS_PREFIX=aarch64-linux-gnu- OS_NAME=Linux OS_ARCH=aarch64
clean-native-linux32:
$(MAKE) clean-native OS_NAME=Linux OS_ARCH=x86

View File

@ -1,6 +1,6 @@
TARGET:=target
SRC:=src/main/java
include $(SRC)/org/xerial/snappy/VERSION
include src/main/resources/org/xerial/snappy/VERSION
ifndef JAVA_HOME
$(error Set JAVA_HOME environment variable)
@ -42,7 +42,7 @@ endif
# os=Default is meant to be generic unix/linux
known_os_archs := Linux-x86 Linux-x86_64 Linux-arm Linux-armhf Linux-ppc64 Mac-x86 Mac-x86_64 FreeBSD-x86_64 Windows-x86 Windows-x86_64 SunOS-x86 SunOS-sparc SunOS-x86_64
known_os_archs := Linux-x86 Linux-x86_64 Linux-arm Linux-armhf Linux-ppc Linux-ppc64 Mac-x86 Mac-x86_64 FreeBSD-x86_64 Windows-x86 Windows-x86_64 SunOS-x86 SunOS-sparc SunOS-x86_64 AIX-ppc64
os_arch := $(OS_NAME)-$(OS_ARCH)
IBM_JDK_7 := $(findstring IBM, $(shell $(JAVA) -version 2>&1 | grep IBM | grep "JRE 1.7"))
@ -50,12 +50,14 @@ ifeq (,$(findstring $(strip $(os_arch)),$(known_os_archs)))
os_arch := Default
endif
os_folder := $(shell echo $(OS_NAME) | tr A-Z a-z)
ifneq ($(IBM_JDK_7),)
$(shell mkdir -p $(IBM_JDK_LIB))
$(shell cp $(JAVA_HOME)/include/jniport.h $(IBM_JDK_LIB))
$(shell sed -i "s|#define JNIEXPORT *$$|#define JNIEXPORT __attribute__((__visibility__(\"default\")))|" $(IBM_JDK_LIB)/jniport.h)
$(shell sed -i "s|typedef long long jlong;.*|/*typedef long long jlong;*/|" $(IBM_JDK_LIB)/jniport.h)
$(shell cp $(JAVA_HOME)/include/linux/jni_md.h $(IBM_JDK_LIB))
$(shell cp $(JAVA_HOME)/include/$(os_folder)/jni_md.h $(IBM_JDK_LIB))
$(shell sed -i "s|#define JNIEXPORT|#define JNIEXPORT __attribute__((__visibility__(\"default\")))|" $(IBM_JDK_LIB)/jni_md.h)
$(shell sed -i "s|typedef long long jlong;.*|/*typedef long long jlong;*/|" $(IBM_JDK_LIB)/jni_md.h)
endif
@ -92,17 +94,39 @@ Linux-x86_64_LINKFLAGS := -shared -static-libgcc -static-libstdc++
Linux-x86_64_LIBNAME := libsnappyjava.so
Linux-x86_64_SNAPPY_FLAGS :=
Linux-ppc_CXX := g++
Linux-ppc_STRIP := strip
ifeq ($(IBM_JDK_7),)
Linux-ppc_CXXFLAGS := -DHAVE_CONFIG_H -Ilib/inc_linux -I$(JAVA_HOME)/include -Ilib/inc_mac -O2 -fPIC -fvisibility=hidden -m32
else
Linux-ppc_CXXFLAGS := -DHAVE_CONFIG_H -include lib/inc_linux/jni_md.h -include $(IBM_JDK_LIB)/jniport.h -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -O2 -fPIC -m32
endif
Linux-ppc_LINKFLAGS := -shared -static-libgcc -static-libstdc++
Linux-ppc_LIBNAME := libsnappyjava.so
Linux-ppc_SNAPPY_FLAGS :=
Linux-ppc64_CXX := g++
Linux-ppc64_STRIP := strip
ifeq ($(IBM_JDK_7),)
Linux-ppc64_CXXFLAGS := -DHAVE_CONFIG_H -Ilib/inc_linux -I$(JAVA_HOME)/include -Ilib/inc_mac -O2 -fPIC -fvisibility=hidden -m64
else
Linux-ppc64_CXXFLAGS := -DHAVE_CONFIG_H -include $(IBM_JDK_LIB)/jni_md.h -include $(IBM_JDK_LIB)/jniport.h -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -O2 -fPIC
Linux-ppc64_CXXFLAGS := -DHAVE_CONFIG_H -include $(IBM_JDK_LIB)/jni_md.h -include $(IBM_JDK_LIB)/jniport.h -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -O2 -fPIC -m64
endif
Linux-ppc64_LINKFLAGS := -shared -static-libgcc -static-libstdc++
Linux-ppc64_LIBNAME := libsnappyjava.so
Linux-ppc64_SNAPPY_FLAGS :=
AIX-ppc64_CXX := g++
AIX-ppc64_STRIP := strip -X64
AIX-ppc64_LIBNAME := libsnappyjava.a
ifeq ($(IBM_JDK_7),)
AIX-ppc64_CXXFLAGS := -DHAVE_CONFIG_H -Ilib/inc_linux -I$(JAVA_HOME)/include -Ilib/inc_mac -O2 -fPIC -fvisibility=hidden -m64
else
AIX-ppc64_CXXFLAGS := -DHAVE_CONFIG_H -I$(JAVA_HOME)/include/aix -Ilib/inc_ibm -I$(JAVA_HOME)/include -Ilib/inc_mac -O2 -fPIC -maix64
endif
AIX-ppc64_LINKFLAGS := -shared -static-libgcc -static-libstdc++ -lcrypt
AIX-ppc64_SNAPPY_FLAGS :=
SunOS-x86_CXX := g++
SunOS-x86_STRIP := strip
SunOS-x86_CXXFLAGS := -include lib/inc_linux/jni_md.h -I$(JAVA_HOME)/include -O2 -fPIC -fvisibility=hidden
@ -193,3 +217,4 @@ ifneq ($(jni_include),)
CXXFLAGS := $(CXXFLAGS) -I"$(jni_include)"
endif

View File

@ -1,9 +1,23 @@
## Features under consideration
* `SnappyIndexer` for parallel compression/decompression
* CUI commands (snap/unsnap)
Since vesion 1.1.0.x, Java 6 (1.6) or higher is required.
## snappy-java-1.1.2-RC1 (13 May 2015)
* SnappyInputStream now supports reading concatenated compressed results of SnappyOutputStream
* There has been no compressed format change since 1.0.5.x. So You can read the compressed results interchangeablly between these versions.
* Fixes a problem when java.io.tmpdir does not exist.
## snappy-java-1.1.1.7 (14 Apr 2015)
* Fixes #100
## snappy-java-1.1.1.6 (26 Oct 2014)
* Fixes #88, #89, #90 and #91
* Fixed the broken build of 1.1.1.4 and memory leak bug 1.1.1.5 (so never use these versions)
## snappy-java-1.0.5.4 (12 September 2014)
* Embedded libstdc++ for Linux/amd64 native library (hotfix to 1.0.5.x series)
## snappy-java-1.1.1.3 (19 July 2014)
* Improved the performance of SnappyOutputStream
## snappy-java-1.1.1 (4 July 2014)
* Added Snappy framing format support: SnappyFramedInput/OutputStream
* Added native libraries for PowerPC, IBM-AIX 6.4, SunOS.

View File

@ -2,9 +2,11 @@ The snappy-java is a Java port of the snappy
<http://code.google.com/p/snappy/>, a fast C++ compresser/decompresser developed by Google.
## Features
* Fast compression/decompression tailored to 64-bit CPU architecture.
* Fast compression/decompression around 200~400MB/sec.
* Less memory usage. SnappyOutputStream uses only 32KB+ in default.
* JNI-based implementation to achieve comparable performance to the native C++ version.
* Although snappy-java uses JNI, it can be used safely with multiple class loaders (e.g. Tomcat, etc.).
* Although snappy-java uses JNI, it can be used safely with multiple class loaders (e.g. Tomcat, etc.).
* Compression/decompression of Java primitive arrays (`float[]`, `double[]`, `int[]`, `short[]`, `long[]`, etc.)
* Portable across various operating systems; Snappy-java contains native libraries built for Window/Mac/Linux (64-bit). snappy-java loads one of these libraries according to your machine environment (It looks system properties, `os.name` and `os.arch`).
* Simple usage. Add the snappy-java-(version).jar file to your classpath. Then call compression/decompression methods in `org.xerial.snappy.Snappy`.
* [Framing-format support](http://snappy.googlecode.com/svn/trunk/framing_format.txt) (Since 1.1.0 version)
@ -17,10 +19,8 @@ The snappy-java is a Java port of the snappy
* Here are some [benchmark results](https://github.com/ning/jvm-compressor-benchmark/wiki), comparing
snappy-java and the other compressors
`LZO-java`/`LZF`/`QuickLZ`/`Gzip`/`Bzip2`. Thanks [Tatu Saloranta @cotowncoder](http://twitter.com/#!/cowtowncoder) for providing the benchmark suite.
* The benchmark result indicates snappy-java is the fastest compreesor/decompressor in Java
* <http://ning.github.com/jvm-compressor-benchmark/results/canterbury-roundtrip-2011-07-28/index.html>
* The decompression speed is twice as fast as the others:
* <http://ning.github.com/jvm-compressor-benchmark/results/canterbury-uncompress-2011-07-28/index.html>
* The benchmark result indicates snappy-java is the fastest compreesor/decompressor in Java: http://ning.github.com/jvm-compressor-benchmark/results/canterbury-roundtrip-2011-07-28/index.html
* The decompression speed is twice as fast as the others: http://ning.github.com/jvm-compressor-benchmark/results/canterbury-uncompress-2011-07-28/index.html
## Download
@ -29,10 +29,27 @@ The snappy-java is a Java port of the snappy
The current stable version is available from here:
* Release version: http://central.maven.org/maven2/org/xerial/snappy/snappy-java/
* (Old archives are here: http://code.google.com/p/snappy-java/downloads/list)
* Snapshot version (the latest beta version): https://oss.sonatype.org/content/repositories/snapshots/org/xerial/snappy/snappy-java/
For Maven user, see [pom.xml example](#using-with-maven).
### Using with Maven
* Snappy-java is available from Maven's central repository: <http://central.maven.org/maven2/org/xerial/snappy/snappy-java>
Add the following dependency to your pom.xml:
<dependency>
<groupId>org.xerial.snappy</groupId>
<artifactId>snappy-java</artifactId>
<version>1.1.2-RC1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
### Using with sbt
```
libraryDependencies += "org.xerial.snappy" % "snappy-java" % "1.1.2-RC1"
```
## Usage
First, import `org.xerial.snapy.Snappy` in your Java code:
@ -56,9 +73,18 @@ System.out.println(result);
In addition, high-level methods (`Snappy.compress(String)`, `Snappy.compress(float[] ..)` etc. ) and low-level ones (e.g. `Snappy.rawCompress(.. )`, `Snappy.rawUncompress(..)`, etc.), which minimize memory copies, can be used.
### Stream-based API
Stream-based compressor/decompressor `SnappyFramedOutputStream`/`SnappyFramedInputStream` are also available for reading/writing large data sets.
Stream-based compressor/decompressor `SnappyOutputStream`/`SnappyInputStream` are also available for reading/writing large data sets. `SnappyFramedOutputStream`/`SnappyFramedInputStream` can be used for the [framing format](https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt).
* See also [Javadoc API](https://oss.sonatype.org/service/local/repositories/releases/archive/org/xerial/snappy/snappy-java/1.1.0/snappy-java-1.1.0-javadoc.jar/!/index.html)
* See also [Javadoc API](https://oss.sonatype.org/service/local/repositories/releases/archive/org/xerial/snappy/snappy-java/1.1.1.6/snappy-java-1.1.1.6-javadoc.jar/!/index.html)
#### Compatibility Notes
* `SnappyOutputStream` and `SnappyInputStream` use `[magic header:16 bytes]([block size:int32][compressed data:byte array])*` format. You can read the result of `Snappy.compress` with `SnappyInputStream`, but you cannot read the compressed data generated by `SnappyOutputStream` with `Snappy.uncompress`. Here is the compatibility matrix of data foramt:
| Write\Read | `Snappy.uncompress` | `SnappyInputStream` | `SnappyFramedInputStream` |
| --------------- |:-------------------:|:------------------:|:-----------------------:|
| `Snappy.compress` | ok | ok | x |
| `SnappyOutputStream` | x | ok | x |
| `SnappyFramedOutputStream` | x | x | ok |
### Setting classpath
If you have snappy-java-(VERSION).jar in the current directory, use `-classpath` option as follows:
@ -68,24 +94,6 @@ If you have snappy-java-(VERSION).jar in the current directory, use `-classpath`
$ javac -classpath ".:snappy-java-(VERSION).jar" Sample.java # in Mac or Linux
### Using with Maven
* Snappy-java is available from Maven's central repository: <http://repo1.maven.org/maven2/org/xerial/snappy/snappy-java>
Add the following dependency to your pom.xml:
<dependency>
<groupId>org.xerial.snappy</groupId>
<artifactId>snappy-java</artifactId>
<version>(version)</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
### Using with sbt
```
libraryDependencies += "org.xerial.snappy" % "snappy-java" % "(version)"
```
## Public discussion group

View File

@ -1,6 +1,3 @@
import SonatypeKeys._
sonatypeSettings
name := "snappy-java"
@ -10,7 +7,7 @@ organizationName := "xerial.org"
description := "snappy-java: A fast compression/decompression library"
profileName := "org.xerial"
sonatypeProfileName := "org.xerial"
pomExtra := {
<url>https://github.comm/xerial/snappy-java</url>
@ -47,11 +44,21 @@ pomExtra := {
</scm>
}
scalaVersion := "2.11.6"
javacOptions in (Compile, compile) ++= Seq("-encoding", "UTF-8", "-Xlint:unchecked", "-Xlint:deprecation", "-source", "1.6", "-target", "1.6")
javacOptions in doc := {
val opts = Seq("-source", "1.6")
if (scala.util.Properties.isJavaAtLeast("1.8"))
opts ++ Seq("-Xdoclint:none")
else
opts
}
testOptions += Tests.Argument(TestFrameworks.JUnit, "-q", "-v")
//concurrentRestrictions in Global := Seq(Tags.limit(Tags.Test, 1))
concurrentRestrictions in Global := Seq(Tags.limit(Tags.Test, 1))
autoScalaLibrary := false
@ -64,7 +71,9 @@ incOptions := incOptions.value.withNameHashing(true)
libraryDependencies ++= Seq(
"junit" % "junit" % "4.8.2" % "test",
"org.codehaus.plexus" % "plexus-classworlds" % "2.4" % "test",
"org.xerial" % "xerial-core" % "1.0.21" % "test",
"org.xerial.java" % "xerial-core" % "2.1" % "test",
"org.xerial" % "xerial-core" % "3.2.3" % "test",
"org.scalatest" % "scalatest_2.11" % "2.2.0" % "test",
"org.osgi" % "org.osgi.core" % "4.3.0" % "provided",
"com.novocode" % "junit-interface" % "0.10" % "test"
)
@ -72,7 +81,7 @@ libraryDependencies ++= Seq(
osgiSettings
OsgiKeys.exportPackage := Seq("org.xerial.snappy")
OsgiKeys.exportPackage := Seq("org.xerial.snappy", "org.xerial.snappy.buffer")
OsgiKeys.bundleSymbolicName := "org.xerial.snappy.snappy-java"
@ -88,9 +97,11 @@ OsgiKeys.additionalHeaders := Map(
"org/xerial/snappy/native/Mac/x86_64/libsnappyjava.jnilib;osname=macosx;processor=x86-64",
"org/xerial/snappy/native/Linux/x86_64/libsnappyjava.so;osname=linux;processor=x86-64",
"org/xerial/snappy/native/Linux/x86/libsnappyjava.so;osname=linux;processor=x86",
"org/xerial/snappy/native/Linux/aarch64/libsnappyjava.so;osname=linux;processor=aarch64",
"org/xerial/snappy/native/Linux/arm/libsnappyjava.so;osname=linux;processor=arm",
"org/xerial/snappy/native/Linux/ppc64/libsnappyjava.so;osname=linux;processor=ppc64",
"org/xerial/snappy/native/Linux/ppc64le/libsnappyjava.so;osname=linux;processor=ppc64le",
"org/xerial/snappy/native/AIX/ppc64/libsnappyjava.a;osname=aix;processor=ppc64",
"org/xerial/snappy/native/SunOS/x86/libsnappyjava.so;osname=sunos;processor=x86",
"org/xerial/snappy/native/SunOS/x86_64/libsnappyjava.so;osname=sunos;processor=x86-64",
"org/xerial/snappy/native/SunOS/sparc/libsnappyjava.so;osname=sunos;processor=sparc"
@ -100,3 +111,23 @@ OsgiKeys.additionalHeaders := Map(
"Bundle-ActivationPolicy" -> "lazy",
"Bundle-Name" -> "snappy-java: A fast compression/decompression library"
)
import ReleaseTransformations._
import sbtrelease._
releaseTagName := { (version in ThisBuild).value }
releaseProcess := Seq[ReleaseStep](
checkSnapshotDependencies,
inquireVersions,
runClean,
runTest,
setReleaseVersion,
commitReleaseVersion,
tagRelease,
ReleaseStep(action = Command.process("publishSigned", _)),
setNextVersion,
commitNextVersion,
ReleaseStep(action = Command.process("sonatypeReleaseAll", _)),
pushChanges
)

53
lib/inc_ibm/jni_md.h Normal file
View File

@ -0,0 +1,53 @@
/*===========================================================================
* Licensed Materials - Property of IBM
* "Restricted Materials of IBM"
*
* IBM SDK, Java(tm) Technology Edition, v7
* (C) Copyright IBM Corp. 2014, 2014. All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or disclosure
* restricted by GSA ADP Schedule Contract with IBM Corp.
*===========================================================================
*/
/*
* Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_
#define JNIEXPORT __attribute__((__visibility__("default")))
#define JNIIMPORT
#define JNICALL
typedef int jint;
#ifdef _LP64 /* 64-bit Solaris */
typedef long jlong;
#else
/*typedef long long jlong;*/
#endif
typedef signed char jbyte;
#endif /* !_JAVASOFT_JNI_MD_H_ */

56
lib/inc_ibm/jniport.h Normal file
View File

@ -0,0 +1,56 @@
/*******************************************************************************
* Licensed Materials - Property of IBM
* "Restricted Materials of IBM"
*
* (c) Copyright IBM Corp. 1991, 2014 All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or disclosure
* restricted by GSA ADP Schedule Contract with IBM Corp.
*******************************************************************************/
#ifndef jniport_h
#define jniport_h
#if defined(WIN32) || defined(_WIN32) || defined(RIM386) || (defined(BREW) && defined(AEE_SIMULATOR))
#define JNIEXPORT __declspec(dllexport)
#define JNICALL __stdcall
typedef signed char jbyte;
typedef int jint;
typedef __int64 jlong;
#else
#define JNIEXPORT __attribute__((__visibility__("default")))
typedef signed char jbyte;
/*typedef long long jlong;*/
#ifdef BREW
#include "AEEFile.h"
#define FILE IFile
#endif
typedef int jint;
#endif /* WIN32 */
#ifndef JNICALL
#define JNICALL
#endif
#ifndef JNIEXPORT
#define JNIEXPORT __attribute__((__visibility__("default")))
#endif
#ifndef JNIIMPORT
#define JNIIMPORT
#endif
#ifdef _JNI_IMPLEMENTATION_
#define _JNI_IMPORT_OR_EXPORT_ JNIEXPORT
#else
#define _JNI_IMPORT_OR_EXPORT_ JNIIMPORT
#endif
#endif /* jniport_h */

View File

@ -1,2 +1,2 @@
sbt.version=0.13.5
sbt.version=0.13.8

View File

@ -1,9 +1,9 @@
addSbtPlugin("com.github.gseitz" % "sbt-release" % "0.7.1")
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.0")
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.2.1")
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.5.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.3")
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
addSbtPlugin("de.johoop" % "findbugs4sbt" % "1.3.0")

10
sbt
View File

@ -4,8 +4,8 @@
# Author: Paul Phillips <paulp@typesafe.com>
# todo - make this dynamic
declare -r sbt_release_version="0.13.1"
declare -r sbt_unreleased_version="0.13.2-SNAPSHOT" # -sbt-dev doesn't work at present
declare -r sbt_release_version="0.13.8"
declare -r sbt_unreleased_version="0.13.8-SNAPSHOT" # -sbt-dev doesn't work at present
declare -r buildProps="project/build.properties"
declare sbt_jar sbt_dir sbt_create sbt_launch_dir
@ -119,12 +119,12 @@ init_default_option_file () {
declare -r cms_opts="-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC"
declare -r jit_opts="-XX:ReservedCodeCacheSize=256m -XX:+TieredCompilation"
declare -r default_jvm_opts="-Dfile.encoding=UTF8 -XX:MaxPermSize=384m -Xms512m -Xmx1536m -Xss2m $jit_opts $cms_opts"
declare -r default_jvm_opts="-ea -Dfile.encoding=UTF8 -Xms512m -Xmx1536m -Xss2m $jit_opts $cms_opts"
declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy"
declare -r latest_28="2.8.2"
declare -r latest_29="2.9.3"
declare -r latest_210="2.10.3"
declare -r latest_211="2.11.0-M5"
declare -r latest_210="2.10.5"
declare -r latest_211="2.11.6"
declare -r script_path="$(get_script_path "$BASH_SOURCE")"
declare -r script_name="${script_path##*/}"

View File

@ -43,6 +43,7 @@ public class OSInfo
public static final String IA64_32 = "ia64_32";
public static final String IA64 = "ia64";
public static final String PPC = "ppc";
public static final String PPC64 = "ppc64";
static {
// x86 mappings
@ -75,6 +76,11 @@ public class OSInfo
archMapping.put("power_rs", PPC);
// TODO: PowerPC 64bit mappings
archMapping.put(PPC64, PPC64);
archMapping.put("power64", PPC64);
archMapping.put("powerpc64", PPC64);
archMapping.put("power_pc64", PPC64);
archMapping.put("power_rs64", PPC64);
}
@ -140,7 +146,11 @@ public class OSInfo
else if (osName.contains("Linux")) {
return "Linux";
}
else {
else if (osName.contains("AIX")) {
return "AIX";
}
else {
return osName.replaceAll("\\W", "");
}
}

View File

@ -50,7 +50,15 @@ import java.util.Arrays;
public class SnappyCodec
{
public static final byte[] MAGIC_HEADER = new byte[] { -126, 'S', 'N', 'A', 'P', 'P', 'Y', 0 };
public static final int MAGIC_LEN = 8;
public static final int MAGIC_LEN = MAGIC_HEADER.length;
public static final int HEADER_SIZE = MAGIC_LEN + 8;
public static final int MAGIC_HEADER_HEAD = SnappyOutputStream.readInt(MAGIC_HEADER, 0);
public static final int MAGIC_HEADER_TAIL = SnappyOutputStream.readInt(MAGIC_HEADER, 4);
static {
assert(MAGIC_HEADER_HEAD < 0);
}
public static final int DEFAULT_VERSION = 1;
public static final int MINIMUM_COMPATIBLE_VERSION = 1;
@ -58,11 +66,25 @@ public class SnappyCodec
public final byte[] magic;
public final int version;
public final int compatibleVersion;
private final byte[] headerArray;
private SnappyCodec(byte[] magic, int version, int compatibleVersion) {
this.magic = magic;
this.version = version;
this.compatibleVersion = compatibleVersion;
ByteArrayOutputStream header = new ByteArrayOutputStream(HEADER_SIZE);
DataOutputStream d = new DataOutputStream(header);
try {
d.write(magic, 0, MAGIC_LEN);
d.writeInt(version);
d.writeInt(compatibleVersion);
d.close();
}
catch(IOException e) {
throw new RuntimeException(e);
}
headerArray = header.toByteArray();
}
@Override
@ -71,17 +93,17 @@ public class SnappyCodec
}
public static int headerSize() {
return MAGIC_LEN + 4 * 2;
return HEADER_SIZE;
}
public void writeHeader(OutputStream out) throws IOException {
ByteArrayOutputStream header = new ByteArrayOutputStream();
DataOutputStream d = new DataOutputStream(header);
d.write(magic, 0, MAGIC_LEN);
d.writeInt(version);
d.writeInt(compatibleVersion);
d.close();
out.write(header.toByteArray(), 0, header.size());
public int writeHeader(byte[] dst, int dstOffset) {
System.arraycopy(headerArray, 0, dst, dstOffset, headerArray.length);
return headerArray.length;
}
public int writeHeader(OutputStream out) throws IOException {
out.write(headerArray, 0, headerArray.length);
return headerArray.length;
}
public boolean isValidMagicHeader() {
@ -97,8 +119,6 @@ public class SnappyCodec
return new SnappyCodec(magic, version, compatibleVersion);
}
public static SnappyCodec currentHeader() {
return new SnappyCodec(MAGIC_HEADER, DEFAULT_VERSION, MINIMUM_COMPATIBLE_VERSION);
}
public static SnappyCodec currentHeader = new SnappyCodec(MAGIC_HEADER, DEFAULT_VERSION, MINIMUM_COMPATIBLE_VERSION);
}

View File

@ -38,7 +38,11 @@ public enum SnappyErrorCode {
PARSING_ERROR(2),
NOT_A_DIRECT_BUFFER(3),
OUT_OF_MEMORY(4),
FAILED_TO_UNCOMPRESS(5);
FAILED_TO_UNCOMPRESS(5),
EMPTY_INPUT(6),
INCOMPATIBLE_VERSION(7),
INVALID_CHUNK_SIZE(8)
;
public final int id;

View File

@ -0,0 +1,23 @@
package org.xerial.snappy;
import java.io.IOException;
/**
* Enhanced IOException with SnappyErrorCode
*/
public class SnappyIOException extends IOException {
private final SnappyErrorCode errorCode;
public SnappyIOException(SnappyErrorCode errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
@Override
public String getMessage() {
return String.format("[%s] %s", errorCode.name(), super.getMessage());
}
public SnappyErrorCode getErrorCode() { return errorCode; }
}

View File

@ -45,7 +45,7 @@ public class SnappyInputStream extends InputStream
private int uncompressedCursor = 0;
private int uncompressedLimit = 0;
private byte[] chunkSizeBuf = new byte[4];
private byte[] header = new byte[SnappyCodec.headerSize()];
/**
* Create a filter for reading compressed data as a uncompressed stream
@ -73,7 +73,6 @@ public class SnappyInputStream extends InputStream
}
protected void readHeader() throws IOException {
byte[] header = new byte[SnappyCodec.headerSize()];
int readBytes = 0;
while (readBytes < header.length) {
int ret = in.read(header, readBytes, header.length - readBytes);
@ -82,31 +81,45 @@ public class SnappyInputStream extends InputStream
readBytes += ret;
}
// Quick test of the header
// Quick test of the header
if(readBytes == 0) {
// Snappy produces at least 1-byte result. So the empty input is not a valid input
throw new SnappyIOException(SnappyErrorCode.EMPTY_INPUT, "Cannot decompress empty stream");
}
if (readBytes < header.length || header[0] != SnappyCodec.MAGIC_HEADER[0]) {
// do the default uncompression
readFully(header, readBytes);
return;
}
SnappyCodec codec = SnappyCodec.readHeader(new ByteArrayInputStream(header));
if (codec.isValidMagicHeader()) {
// The input data is compressed by SnappyOutputStream
if (codec.version < SnappyCodec.MINIMUM_COMPATIBLE_VERSION) {
throw new IOException(String.format(
"compressed with imcompatible codec version %d. At least version %d is required",
codec.version, SnappyCodec.MINIMUM_COMPATIBLE_VERSION));
}
}
else {
if(!isValidHeader(header)) {
// (probably) compressed by Snappy.compress(byte[])
readFully(header, readBytes);
return;
}
}
private static boolean isValidHeader(byte[] header) throws IOException {
SnappyCodec codec = SnappyCodec.readHeader(new ByteArrayInputStream(header));
if (codec.isValidMagicHeader()) {
// The input data is compressed by SnappyOutputStream
if(codec.version < SnappyCodec.MINIMUM_COMPATIBLE_VERSION) {
throw new SnappyIOException(SnappyErrorCode.INCOMPATIBLE_VERSION, String.format(
"Compressed with an incompatible codec version %d. At least version %d is required",
codec.version, SnappyCodec.MINIMUM_COMPATIBLE_VERSION));
}
return true;
}
else
return false;
}
protected void readFully(byte[] fragment, int fragmentLength) throws IOException {
// read the entire input data to the buffer
if(fragmentLength == 0) {
finishedReading = true;
return;
}
// read the entire input data to the buffer
compressed = new byte[Math.max(8 * 1024, fragmentLength)]; // 8K
System.arraycopy(fragment, 0, compressed, 0, fragmentLength);
int cursor = fragmentLength;
@ -316,6 +329,26 @@ public class SnappyInputStream extends InputStream
return read(d, 0, d.length);
}
/**
* Read next len bytes
* @param dest
* @param offset
* @param len
* @return read bytes
*/
private int readNext(byte[] dest, int offset, int len) throws IOException {
int readBytes = 0;
while (readBytes < len) {
int ret = in.read(dest, readBytes + offset, len - readBytes);
if (ret == -1) {
finishedReading = true;
return readBytes;
}
readBytes += ret;
}
return readBytes;
}
protected boolean hasNextChunk() throws IOException {
if (finishedReading)
return false;
@ -323,16 +356,24 @@ public class SnappyInputStream extends InputStream
uncompressedCursor = 0;
uncompressedLimit = 0;
int readBytes = 0;
while (readBytes < 4) {
int ret = in.read(chunkSizeBuf, readBytes, 4 - readBytes);
if (ret == -1) {
finishedReading = true;
int readBytes = readNext(header, 0, 4);
if(readBytes < 4)
return false;
int chunkSize = SnappyOutputStream.readInt(header, 0);
if(chunkSize == SnappyCodec.MAGIC_HEADER_HEAD) {
// Concatenated data
int remainingHeaderSize = SnappyCodec.headerSize() - 4;
readBytes = readNext(header, 4, remainingHeaderSize);
if(readBytes < remainingHeaderSize)
return false;
if(isValidHeader(header))
return hasNextChunk();
else
return false;
}
readBytes += ret;
}
int chunkSize = SnappyOutputStream.readInt(chunkSizeBuf, 0);
// extend the compressed data buffer size
if (compressed == null || chunkSize > compressed.length) {
compressed = new byte[chunkSize];
@ -347,20 +388,15 @@ public class SnappyInputStream extends InputStream
if (readBytes < chunkSize) {
throw new IOException("failed to read chunk");
}
try {
int uncompressedLength = Snappy.uncompressedLength(compressed, 0, chunkSize);
if (uncompressed == null || uncompressedLength > uncompressed.length) {
uncompressed = new byte[uncompressedLength];
}
int actualUncompressedLength = Snappy.uncompress(compressed, 0, chunkSize, uncompressed, 0);
if (uncompressedLength != actualUncompressedLength) {
throw new IOException("invalid uncompressed byte size");
}
uncompressedLimit = actualUncompressedLength;
int uncompressedLength = Snappy.uncompressedLength(compressed, 0, chunkSize);
if (uncompressed == null || uncompressedLength > uncompressed.length) {
uncompressed = new byte[uncompressedLength];
}
catch (IOException e) {
throw new IOException("failed to uncompress the chunk: " + e.getMessage());
int actualUncompressedLength = Snappy.uncompress(compressed, 0, chunkSize, uncompressed, 0);
if (uncompressedLength != actualUncompressedLength) {
throw new SnappyIOException(SnappyErrorCode.INVALID_CHUNK_SIZE, String.format("expected %,d bytes, but decompressed chunk has %,d bytes", uncompressedLength, actualUncompressedLength));
}
uncompressedLimit = actualUncompressedLength;
return true;
}

View File

@ -300,11 +300,13 @@ public class SnappyLoader
}
// Temporary folder for the native lib. Use the value of org.xerial.snappy.tempdir or java.io.tmpdir
String tempFolder = new File(System.getProperty(KEY_SNAPPY_TEMPDIR,
System.getProperty("java.io.tmpdir"))).getAbsolutePath();
File tempFolder = new File(System.getProperty(KEY_SNAPPY_TEMPDIR, System.getProperty("java.io.tmpdir")));
if (!tempFolder.exists()) {
tempFolder.mkdir();
}
// Extract and load a native library inside the jar file
return extractLibraryFile(snappyNativeLibraryPath, snappyNativeLibraryName, tempFolder);
return extractLibraryFile(snappyNativeLibraryPath, snappyNativeLibraryName, tempFolder.getAbsolutePath());
}

View File

@ -1,315 +1,332 @@
/*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito
*
* Licensed 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.
*--------------------------------------------------------------------------*/
//--------------------------------------
// XerialJ
//
// SnappyOutputStream.java
// Since: 2011/03/31 17:44:10
//
// $URL$
// $Author$
//--------------------------------------
package org.xerial.snappy;
import java.io.IOException;
import java.io.OutputStream;
/**
* This class implements a stream filter for writing compressed data using
* Snappy.
*
* The input data is blocked into 32kb size (in default), and each block is
* compressed and then passed to the given {@link OutputStream}.
*
* The output data format is:
* <ol>
* <li>snappy codec header defined in {@link SnappyCodec} (8 bytes)
* <li>compressed block 1 : a pair of (compressed data size [4 byte integer.
* Big-endian], compressed data...)
* <li>compressed block 2
* <li>...
* </ol>
*
* Note that the compressed data created by {@link SnappyOutputStream} cannot be
* uncompressed by {@link Snappy#uncompress(byte[])} since the output formats of
* {@link Snappy#compress(byte[])} and {@link SnappyOutputStream} are different.
* Use {@link SnappyInputStream} for uncompress the data generated by
* {@link SnappyOutputStream}.
*
* @author leo
*
*/
public class SnappyOutputStream extends OutputStream
{
static final int DEFAULT_BLOCK_SIZE = 32 * 1024; // Use 32kb for the default block size
protected final OutputStream out;
private final int blockSize;
private int cursor = 0;
protected byte[] uncompressed;
protected byte[] compressed;
public SnappyOutputStream(OutputStream out) throws IOException {
this(out, DEFAULT_BLOCK_SIZE);
}
/**
* @param out
* @param blockSize
* byte size of the internal buffer size
* @throws IOException
*/
public SnappyOutputStream(OutputStream out, int blockSize) throws IOException {
this.out = out;
this.blockSize = blockSize;
uncompressed = new byte[blockSize];
compressed = new byte[Snappy.maxCompressedLength(blockSize)];
writeHeader();
}
protected void writeHeader() throws IOException {
SnappyCodec.currentHeader().writeHeader(out);
}
/**
* Writes len bytes from the specified byte array starting at offset off to
* this output stream. The general contract for write(b, off, len) is that
* some of the bytes in the array b are written to the output stream in
* order; element b[off] is the first byte written and b[off+len-1] is the
* last byte written by this operation.
*/
/* (non-Javadoc)
* @see java.io.OutputStream#write(byte[], int, int)
*/
@Override
public void write(byte[] b, int off, int len) throws IOException {
rawWrite(b, off, len);
}
/**
* Compress the input long array data
*
* @param d
* input array
* @param off
* offset in the array
* @param len
* the number of elements in the array to copy
* @throws IOException
*/
public void write(long[] d, int off, int len) throws IOException {
rawWrite(d, off * 8, len * 8);
}
/**
* Compress the input double array data
*
* @param f
* input array
* @param off
* offset in the array
* @param len
* the number of elements in the array to copy
* @throws IOException
*/
public void write(double[] f, int off, int len) throws IOException {
rawWrite(f, off * 8, len * 8);
}
/**
* Compress the input float array data
*
* @param f
* input array
* @param off
* offset in the array
* @param len
* the number of elements in the array to copy
* @throws IOException
*/
public void write(float[] f, int off, int len) throws IOException {
rawWrite(f, off * 4, len * 4);
}
/**
* Compress the input int array data
*
* @param f
* input array
* @param off
* offset in the array
* @param len
* the number of elements in the array to copy
* @throws IOException
*/
public void write(int[] f, int off, int len) throws IOException {
rawWrite(f, off * 4, len * 4);
}
/**
* Compress the input short array data
*
* @param f
* input array
* @param off
* offset in the array
* @param len
* the number of elements in the array to copy
* @throws IOException
*/
public void write(short[] f, int off, int len) throws IOException {
rawWrite(f, off * 2, len * 2);
}
/**
* Compress the input array data
*
* @param d
* @throws IOException
*/
public void write(long[] d) throws IOException {
write(d, 0, d.length);
}
/**
* Compress the input array data
*
* @param f
* @throws IOException
*/
public void write(double[] f) throws IOException {
write(f, 0, f.length);
}
/**
* Compress the input array data
*
* @param f
* @throws IOException
*/
public void write(float[] f) throws IOException {
write(f, 0, f.length);
}
/**
* Compress the input array data
*
* @param f
* @throws IOException
*/
public void write(int[] f) throws IOException {
write(f, 0, f.length);
}
/**
* Compress the input array data
*
* @param f
* @throws IOException
*/
public void write(short[] f) throws IOException {
write(f, 0, f.length);
}
/**
* Compress the raw byte array data.
*
* @param array
* array data of any type (e.g., byte[], float[], long[], ...)
* @param byteOffset
* @param byteLength
* @throws IOException
*/
public void rawWrite(Object array, int byteOffset, int byteLength) throws IOException {
for (int readBytes = 0; readBytes < byteLength;) {
int copyLen = Math.min(uncompressed.length - cursor, byteLength - readBytes);
Snappy.arrayCopy(array, byteOffset + readBytes, copyLen, uncompressed, cursor);
readBytes += copyLen;
cursor += copyLen;
if (cursor >= uncompressed.length) {
dump();
}
}
}
/**
* Writes the specified byte to this output stream. The general contract for
* write is that one byte is written to the output stream. The byte to be
* written is the eight low-order bits of the argument b. The 24 high-order
* bits of b are ignored.
*/
/* (non-Javadoc)
* @see java.io.OutputStream#write(int)
*/
@Override
public void write(int b) throws IOException {
if (cursor >= uncompressed.length) {
dump();
}
uncompressed[cursor++] = (byte) b;
}
/* (non-Javadoc)
* @see java.io.OutputStream#flush()
*/
@Override
public void flush() throws IOException {
dump();
out.flush();
}
static void writeInt(OutputStream out, int value) throws IOException {
out.write((value >> 24) & 0xFF);
out.write((value >> 16) & 0xFF);
out.write((value >> 8) & 0xFF);
out.write((value >> 0) & 0xFF);
}
static int readInt(byte[] buffer, int pos) {
int b1 = (buffer[pos] & 0xFF) << 24;
int b2 = (buffer[pos + 1] & 0xFF) << 16;
int b3 = (buffer[pos + 2] & 0xFF) << 8;
int b4 = buffer[pos + 3] & 0xFF;
return b1 | b2 | b3 | b4;
}
protected void dump() throws IOException {
if (cursor <= 0)
return; // no need to dump
// Compress and dump the buffer content
int compressedSize = Snappy.compress(uncompressed, 0, cursor, compressed, 0);
writeInt(out, compressedSize);
out.write(compressed, 0, compressedSize);
cursor = 0;
}
/**
* close the stream
*/
/* (non-Javadoc)
* @see java.io.OutputStream#close()
*/
@Override
public void close() throws IOException {
flush();
super.close();
out.close();
}
}
/*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito
*
* Licensed 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.
*--------------------------------------------------------------------------*/
//--------------------------------------
// XerialJ
//
// SnappyOutputStream.java
// Since: 2011/03/31 17:44:10
//
// $URL$
// $Author$
//--------------------------------------
package org.xerial.snappy;
import org.xerial.snappy.buffer.BufferAllocatorFactory;
import org.xerial.snappy.buffer.BufferAllocator;
import org.xerial.snappy.buffer.CachedBufferAllocator;
import java.io.IOException;
import java.io.OutputStream;
/**
* This class implements a stream filter for writing compressed data using
* Snappy.
* <p>
* The input data is blocked into 32kb size (in default), and each block is
* compressed and then passed to the given {@link OutputStream}.
* </p>
* The output data format is:
* <ol>
* <li>snappy codec header defined in {@link SnappyCodec} (8 bytes)
* <li>compressed block 1 : a pair of (compressed data size [4 byte integer.
* Big-endian], compressed data...)
* <li>compressed block 2
* <li>...
* </ol>
* <p/>
* Note that the compressed data created by {@link SnappyOutputStream} cannot be
* uncompressed by {@link Snappy#uncompress(byte[])} since the output formats of
* {@link Snappy#compress(byte[])} and {@link SnappyOutputStream} are different.
* Use {@link SnappyInputStream} for uncompress the data generated by
* {@link SnappyOutputStream}.
*
* @author leo
*/
public class SnappyOutputStream extends OutputStream {
static final int MIN_BLOCK_SIZE = 1 * 1024;
static final int DEFAULT_BLOCK_SIZE = 32 * 1024; // Use 32kb for the default block size
protected final OutputStream out;
private final int blockSize;
private final BufferAllocator inputBufferAllocator;
private final BufferAllocator outputBufferAllocator;
protected final byte[] inputBuffer;
protected final byte[] outputBuffer;
private int inputCursor = 0;
private int outputCursor = 0;
public SnappyOutputStream(OutputStream out) {
this(out, DEFAULT_BLOCK_SIZE);
}
/**
* @param out
* @param blockSize byte size of the internal buffer size
* @throws IOException
*/
public SnappyOutputStream(OutputStream out, int blockSize) {
this(out, blockSize, CachedBufferAllocator.factory);
}
public SnappyOutputStream(OutputStream out, int blockSize, BufferAllocatorFactory bufferAllocatorFactory) {
this.out = out;
this.blockSize = Math.max(MIN_BLOCK_SIZE, blockSize);
int inputSize = blockSize;
int outputSize = SnappyCodec.HEADER_SIZE + 4 + Snappy.maxCompressedLength(blockSize);
this.inputBufferAllocator = bufferAllocatorFactory.getBufferAllocator(inputSize);
this.outputBufferAllocator = bufferAllocatorFactory.getBufferAllocator(outputSize);
inputBuffer = inputBufferAllocator.allocate(inputSize);
outputBuffer = outputBufferAllocator.allocate(outputSize);
outputCursor = SnappyCodec.currentHeader.writeHeader(outputBuffer, 0);
}
/* (non-Javadoc)
* @see java.io.OutputStream#write(byte[], int, int)
*/
@Override
public void write(byte[] b, int off, int len) throws IOException {
rawWrite(b, off, len);
}
/**
* Compress the input long array data
*
* @param d input array
* @param off offset in the array
* @param len the number of elements in the array to copy
* @throws IOException
*/
public void write(long[] d, int off, int len) throws IOException {
rawWrite(d, off * 8, len * 8);
}
/**
* Compress the input double array data
*
* @param f input array
* @param off offset in the array
* @param len the number of elements in the array to copy
* @throws IOException
*/
public void write(double[] f, int off, int len) throws IOException {
rawWrite(f, off * 8, len * 8);
}
/**
* Compress the input float array data
*
* @param f input array
* @param off offset in the array
* @param len the number of elements in the array to copy
* @throws IOException
*/
public void write(float[] f, int off, int len) throws IOException {
rawWrite(f, off * 4, len * 4);
}
/**
* Compress the input int array data
*
* @param f input array
* @param off offset in the array
* @param len the number of elements in the array to copy
* @throws IOException
*/
public void write(int[] f, int off, int len) throws IOException {
rawWrite(f, off * 4, len * 4);
}
/**
* Compress the input short array data
*
* @param f input array
* @param off offset in the array
* @param len the number of elements in the array to copy
* @throws IOException
*/
public void write(short[] f, int off, int len) throws IOException {
rawWrite(f, off * 2, len * 2);
}
/**
* Compress the input array data
*
* @param d
* @throws IOException
*/
public void write(long[] d) throws IOException {
write(d, 0, d.length);
}
/**
* Compress the input array data
*
* @param f
* @throws IOException
*/
public void write(double[] f) throws IOException {
write(f, 0, f.length);
}
/**
* Compress the input array data
*
* @param f
* @throws IOException
*/
public void write(float[] f) throws IOException {
write(f, 0, f.length);
}
/**
* Compress the input array data
*
* @param f
* @throws IOException
*/
public void write(int[] f) throws IOException {
write(f, 0, f.length);
}
/**
* Compress the input array data
*
* @param f
* @throws IOException
*/
public void write(short[] f) throws IOException {
write(f, 0, f.length);
}
private boolean hasSufficientOutputBufferFor(int inputSize) {
int maxCompressedSize = Snappy.maxCompressedLength(inputSize);
return maxCompressedSize < outputBuffer.length - outputCursor - 4;
}
/**
* Compress the raw byte array data.
*
* @param array array data of any type (e.g., byte[], float[], long[], ...)
* @param byteOffset
* @param byteLength
* @throws IOException
*/
public void rawWrite(Object array, int byteOffset, int byteLength) throws IOException {
int cursor = 0;
while(cursor < byteLength) {
int readLen = Math.min(byteLength - cursor, blockSize - inputCursor);
// copy the input data to uncompressed buffer
if(readLen > 0) {
Snappy.arrayCopy(array, byteOffset + cursor, readLen, inputBuffer, inputCursor);
inputCursor += readLen;
}
if(inputCursor < blockSize)
return;
compressInput();
cursor += readLen;
}
}
/**
* Writes the specified byte to this output stream. The general contract for
* write is that one byte is written to the output stream. The byte to be
* written is the eight low-order bits of the argument b. The 24 high-order
* bits of b are ignored.
*/
/* (non-Javadoc)
* @see java.io.OutputStream#write(int)
*/
@Override
public void write(int b) throws IOException {
if(inputCursor >= inputBuffer.length) {
compressInput();
}
inputBuffer[inputCursor++] = (byte) b;
}
/* (non-Javadoc)
* @see java.io.OutputStream#flush()
*/
@Override
public void flush() throws IOException {
compressInput();
dumpOutput();
out.flush();
}
static void writeInt(byte[] dst, int offset, int v) {
dst[offset] = (byte) ((v >> 24) & 0xFF);
dst[offset + 1] = (byte) ((v >> 16) & 0xFF);
dst[offset + 2] = (byte) ((v >> 8) & 0xFF);
dst[offset + 3] = (byte) ((v >> 0) & 0xFF);
}
static int readInt(byte[] buffer, int pos) {
int b1 = (buffer[pos] & 0xFF) << 24;
int b2 = (buffer[pos + 1] & 0xFF) << 16;
int b3 = (buffer[pos + 2] & 0xFF) << 8;
int b4 = buffer[pos + 3] & 0xFF;
return b1 | b2 | b3 | b4;
}
protected void dumpOutput() throws IOException {
if(outputCursor > 0) {
out.write(outputBuffer, 0, outputCursor);
outputCursor = 0;
}
}
protected void compressInput() throws IOException {
if(inputCursor <= 0) {
return; // no need to dump
}
// Compress and dump the buffer content
if(!hasSufficientOutputBufferFor(inputCursor)) {
dumpOutput();
}
int compressedSize = Snappy.compress(inputBuffer, 0, inputCursor, outputBuffer, outputCursor + 4);
// Write compressed data size
writeInt(outputBuffer, outputCursor, compressedSize);
outputCursor += 4 + compressedSize;
inputCursor = 0;
}
/**
* close the stream
*/
/* (non-Javadoc)
* @see java.io.OutputStream#close()
*/
@Override
public void close() throws IOException {
try {
flush();
out.close();
} finally {
inputBufferAllocator.release(inputBuffer);
outputBufferAllocator.release(outputBuffer);
}
}
}

View File

@ -1,2 +0,0 @@
VERSION=1.1.1

View File

@ -0,0 +1,11 @@
package org.xerial.snappy.buffer;
/**
* BufferAllocator interface. The implementation of this interface must be thread-safe
*/
public interface BufferAllocator {
public byte[] allocate(int size);
public void release(byte[] buffer);
}

View File

@ -0,0 +1,10 @@
package org.xerial.snappy.buffer;
/**
*
*/
public interface BufferAllocatorFactory {
BufferAllocator getBufferAllocator(int minSize);
}

View File

@ -0,0 +1,61 @@
package org.xerial.snappy.buffer;
import java.lang.ref.SoftReference;
import java.util.*;
/**
* Cached buffer
*/
public class CachedBufferAllocator implements BufferAllocator {
public static BufferAllocatorFactory factory = new BufferAllocatorFactory() {
@Override
public BufferAllocator getBufferAllocator(int bufferSize) {
return CachedBufferAllocator.getAllocator(bufferSize);
}
};
/**
* Use SoftReference so that having this queueTable does not prevent the GC of CachedBufferAllocator instances
*/
public static Map<Integer, SoftReference<CachedBufferAllocator>> queueTable = new HashMap<Integer, SoftReference<CachedBufferAllocator>>();
private final int bufferSize;
private final Deque<byte[]> bufferQueue;
public CachedBufferAllocator(int bufferSize) {
this.bufferSize = bufferSize;
this.bufferQueue = new ArrayDeque<byte[]>();
}
public static synchronized CachedBufferAllocator getAllocator(int bufferSize) {
CachedBufferAllocator result = null;
if (queueTable.containsKey(bufferSize)) {
result = queueTable.get(bufferSize).get();
}
if (result == null) {
result = new CachedBufferAllocator(bufferSize);
queueTable.put(bufferSize, new SoftReference<CachedBufferAllocator>(result));
}
return result;
}
@Override
public byte[] allocate(int size) {
synchronized(this) {
if(bufferQueue.isEmpty()) {
return new byte[size];
}
else {
return bufferQueue.pollFirst();
}
}
}
@Override
public void release(byte[] buffer) {
synchronized(this) {
bufferQueue.addLast(buffer);
}
}
}

View File

@ -0,0 +1,26 @@
package org.xerial.snappy.buffer;
/**
* Simple buffer allocator, which does not reuse the allocated buffer
*/
public class DefaultBufferAllocator implements BufferAllocator {
public static BufferAllocatorFactory factory = new BufferAllocatorFactory() {
public BufferAllocator singleton = new DefaultBufferAllocator();
@Override
public BufferAllocator getBufferAllocator(int bufferSize) {
return singleton;
}
};
@Override
public byte[] allocate(int size) {
return new byte[size];
}
@Override
public void release(byte[] buffer) {
// do nothing
}
}

View File

@ -0,0 +1 @@
VERSION=1.1.2

View File

@ -35,6 +35,7 @@ import java.io.InputStream;
import org.junit.Test;
import org.xerial.util.FileResource;
import org.xerial.util.log.Logger;
import scala.Array;
public class SnappyInputStreamTest
{
@ -62,7 +63,7 @@ public class SnappyInputStreamTest
}
}
public static byte[] biteWiseReadFully(InputStream input) throws IOException {
public static byte[] byteWiseReadFully(InputStream input) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
for (int readData = 0; (readData = input.read()) != -1;) {
@ -108,7 +109,7 @@ public class SnappyInputStreamTest
byte[] compressed = Snappy.compress(orig);
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressed));
byte[] uncompressed = biteWiseReadFully(in);
byte[] uncompressed = byteWiseReadFully(in);
assertEquals(orig.length, uncompressed.length);
assertArrayEquals(orig, uncompressed);
@ -129,4 +130,50 @@ public class SnappyInputStreamTest
in.close();
}
@Test
public void emptyStream() throws Exception {
try {
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(new byte[0]));
byte[] uncompressed = readFully(in);
assertEquals(0, uncompressed.length);
fail("should not reach here");
}
catch(SnappyIOException e) {
assertEquals(SnappyErrorCode.EMPTY_INPUT, e.getErrorCode());
}
}
public static byte[] compressResource(String resourcePath) throws Exception {
ByteArrayOutputStream compressedBuf = new ByteArrayOutputStream();
SnappyOutputStream snappyOut = new SnappyOutputStream(compressedBuf);
byte[] orig = readResourceFile(resourcePath);
snappyOut.write(orig);
snappyOut.close();
return compressedBuf.toByteArray();
}
@Test
public void chunkRead() throws Exception {
byte[] chunk1 = compressResource("alice29.txt");
byte[] chunk2 = compressResource("testdata/calgary/paper6");
byte[] concatenated = new byte[chunk1.length + chunk2.length];
System.arraycopy(chunk1, 0, concatenated, 0, chunk1.length);
System.arraycopy(chunk2, 0, concatenated, chunk1.length, chunk2.length);
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(concatenated));
byte[] uncompressed = readFully(in);
byte[] orig1 = readResourceFile("alice29.txt");
byte[] orig2 = readResourceFile("testdata/calgary/paper6");
assertEquals(orig1.length + orig2.length, uncompressed.length);
byte[] uncompressed1 = new byte[orig1.length];
byte[] uncompressed2 = new byte[orig2.length];
System.arraycopy(uncompressed, 0, uncompressed1, 0, orig1.length);
System.arraycopy(uncompressed, orig1.length, uncompressed2, 0, orig2.length);
assertArrayEquals(orig1, uncompressed1);
assertArrayEquals(orig2, uncompressed2);
}
}

View File

@ -1,188 +1,250 @@
/*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito
*
* Licensed 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.
*--------------------------------------------------------------------------*/
//--------------------------------------
// XerialJ
//
// SnappyOutputStreamTest.java
// Since: 2011/03/31 18:26:31
//
// $URL$
// $Author$
//--------------------------------------
package org.xerial.snappy;
import static org.junit.Assert.*;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import org.junit.Test;
import org.xerial.util.FileResource;
import org.xerial.util.log.Logger;
public class SnappyOutputStreamTest
{
private static Logger _logger = Logger.getLogger(SnappyOutputStreamTest.class);
@Test
public void test() throws Exception {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
SnappyOutputStream sout = new SnappyOutputStream(buf);
BufferedInputStream input = new BufferedInputStream(FileResource.find(SnappyOutputStreamTest.class,
"alice29.txt").openStream());
assertNotNull(input);
ByteArrayOutputStream orig = new ByteArrayOutputStream();
byte[] tmp = new byte[1024];
for (int readBytes = 0; (readBytes = input.read(tmp)) != -1;) {
sout.write(tmp, 0, readBytes);
orig.write(tmp, 0, readBytes); // preserve the original data
}
input.close();
sout.flush();
orig.flush();
int compressedSize = buf.size();
_logger.debug("compressed size: " + compressedSize);
ByteArrayOutputStream decompressed = new ByteArrayOutputStream();
byte[] compressed = buf.toByteArray();
// decompress
for (int cursor = SnappyCodec.headerSize(); cursor < compressed.length;) {
int chunkSize = SnappyOutputStream.readInt(compressed, cursor);
cursor += 4;
byte[] tmpOut = new byte[Snappy.uncompressedLength(compressed, cursor, chunkSize)];
int decompressedSize = Snappy.uncompress(compressed, cursor, chunkSize, tmpOut, 0);
cursor += chunkSize;
decompressed.write(tmpOut);
}
decompressed.flush();
assertEquals(orig.size(), decompressed.size());
assertArrayEquals(orig.toByteArray(), decompressed.toByteArray());
}
@Test
public void bufferSize() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b, 500);
final int bytesToWrite = 5000;
byte[] orig = new byte[bytesToWrite];
for (int i = 0; i < 5000; ++i) {
byte v = (byte) (i % 128);
orig[i] = v;
os.write(v);
}
os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
byte[] buf = new byte[bytesToWrite / 101];
while (is.read(buf) != -1) {}
is.close();
}
@Test
public void longArrayCompress() throws Exception {
long[] l = new long[10];
for (int i = 0; i < l.length; ++i) {
l[i] = i % 3 + i * 11;
}
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b);
os.write(l);
os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
long[] l2 = new long[10];
int readBytes = is.read(l2);
is.close();
assertEquals(10 * 8, readBytes);
assertArrayEquals(l, l2);
}
@Test
public void writeDoubleArray() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b);
double[] orig = new double[] { 1.0, 2.0, 1.4, 0.00343430014, -4.4, 4e-20 };
os.write(orig);
os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
double[] uncompressed = new double[orig.length];
is.read(uncompressed);
is.close();
assertArrayEquals(orig, uncompressed, 0.0);
}
@Test
public void writeFloatArray() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b);
float[] orig = new float[] { 1.0f, 2.0f, 1.4f, 0.00343430014f, -4.4f, 4e-20f };
os.write(orig);
os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
float[] uncompressed = new float[orig.length];
is.read(uncompressed);
is.close();
assertArrayEquals(orig, uncompressed, 0.0f);
}
@Test
public void writeIntArray() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b);
int[] orig = new int[] { 0, -1, -34, 43, 234, 34324, -234 };
os.write(orig);
os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
int[] uncompressed = new int[orig.length];
is.read(uncompressed);
is.close();
assertArrayEquals(orig, uncompressed);
}
@Test
public void writeShortArray() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b);
short[] orig = new short[] { 0, -1, -34, 43, 234, 324, -234 };
os.write(orig);
os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
short[] uncompressed = new short[orig.length];
is.read(uncompressed);
is.close();
assertArrayEquals(orig, uncompressed);
}
}
/*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito
*
* Licensed 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.
*--------------------------------------------------------------------------*/
//--------------------------------------
// XerialJ
//
// SnappyOutputStreamTest.java
// Since: 2011/03/31 18:26:31
//
// $URL$
// $Author$
//--------------------------------------
package org.xerial.snappy;
import static org.junit.Assert.*;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import org.junit.Test;
import org.xerial.util.FileResource;
import org.xerial.util.log.Logger;
public class SnappyOutputStreamTest
{
private static Logger _logger = Logger.getLogger(SnappyOutputStreamTest.class);
@Test
public void test() throws Exception {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
SnappyOutputStream sout = new SnappyOutputStream(buf);
BufferedInputStream input = new BufferedInputStream(FileResource.find(SnappyOutputStreamTest.class,
"alice29.txt").openStream());
assertNotNull(input);
ByteArrayOutputStream orig = new ByteArrayOutputStream();
byte[] tmp = new byte[1024];
for (int readBytes = 0; (readBytes = input.read(tmp)) != -1;) {
sout.write(tmp, 0, readBytes);
orig.write(tmp, 0, readBytes); // preserve the original data
}
input.close();
sout.flush();
orig.flush();
int compressedSize = buf.size();
_logger.debug("compressed size: " + compressedSize);
ByteArrayOutputStream decompressed = new ByteArrayOutputStream();
byte[] compressed = buf.toByteArray();
// decompress
for (int cursor = SnappyCodec.headerSize(); cursor < compressed.length;) {
int chunkSize = SnappyOutputStream.readInt(compressed, cursor);
cursor += 4;
byte[] tmpOut = new byte[Snappy.uncompressedLength(compressed, cursor, chunkSize)];
int decompressedSize = Snappy.uncompress(compressed, cursor, chunkSize, tmpOut, 0);
cursor += chunkSize;
decompressed.write(tmpOut);
}
decompressed.flush();
assertEquals(orig.size(), decompressed.size());
assertArrayEquals(orig.toByteArray(), decompressed.toByteArray());
}
@Test
public void bufferSize() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b, 1500);
final int bytesToWrite = 5000;
byte[] orig = new byte[bytesToWrite];
for (int i = 0; i < 5000; ++i) {
byte v = (byte) (i % 128);
orig[i] = v;
os.write(v);
}
os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
byte[] buf = new byte[bytesToWrite / 101];
while (is.read(buf) != -1) {}
is.close();
}
@Test
public void smallWrites() throws Exception {
byte[] orig = CalgaryTest.readFile("alice29.txt");
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream out = new SnappyOutputStream(b);
for(byte c : orig) {
out.write(c);
}
out.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
byte[] decompressed = new byte[orig.length];
int cursor = 0;
int readLen = 0;
for(int i=0; i < decompressed.length && (readLen = is.read(decompressed, i, decompressed.length-i)) != -1; ) {
i += readLen;
}
is.close();
assertArrayEquals(orig, decompressed);
}
/**
* Compress the input array by passing it chunk-by-chunk to a SnappyOutputStream.
* @param orig the data to compress
* @param maxChunkSize the maximum chunk size, in bytes.
* @return the compressed bytes
*/
private static byte[] compressAsChunks(byte[] orig, int maxChunkSize) throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream out = new SnappyOutputStream(b);
int remaining = orig.length;
for (int start = 0; start < orig.length; start += maxChunkSize) {
out.write(orig, start, remaining < maxChunkSize ? remaining : maxChunkSize);
remaining -= maxChunkSize;
}
out.close();
return b.toByteArray();
}
@Test
public void batchingOfWritesShouldNotAffectCompressedDataSize() throws Exception {
// Regression test for issue #100, a bug where the size of compressed data could be affected
// by the batching of writes to the SnappyOutputStream rather than the total amount of data
// written to the stream.
byte[] orig = CalgaryTest.readFile("alice29.txt");
// Compress the data once so that we know the expected size:
byte[] expectedCompressedData = compressAsChunks(orig, Integer.MAX_VALUE);
// Hardcoding an expected compressed size here will catch regressions that lower the
// compression quality:
assertEquals(91013, expectedCompressedData.length);
// The chunk size should not affect the size of the compressed output:
int[] chunkSizes = new int[] { 1, 100, 1023, 1024, 10000};
for (int chunkSize : chunkSizes) {
byte[] compressedData = compressAsChunks(orig, chunkSize);
assertEquals(String.format("when chunk size = %,d", chunkSize), expectedCompressedData.length, compressedData.length);
assertArrayEquals(expectedCompressedData, compressedData);
}
}
@Test
public void longArrayCompress() throws Exception {
long[] l = new long[10];
for (int i = 0; i < l.length; ++i) {
l[i] = i % 3 + i * 11;
}
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b);
os.write(l);
os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
long[] l2 = new long[10];
int readBytes = is.read(l2);
is.close();
assertEquals(10 * 8, readBytes);
assertArrayEquals(l, l2);
}
@Test
public void writeDoubleArray() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b);
double[] orig = new double[] { 1.0, 2.0, 1.4, 0.00343430014, -4.4, 4e-20 };
os.write(orig);
os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
double[] uncompressed = new double[orig.length];
is.read(uncompressed);
is.close();
assertArrayEquals(orig, uncompressed, 0.0);
}
@Test
public void writeFloatArray() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b);
float[] orig = new float[] { 1.0f, 2.0f, 1.4f, 0.00343430014f, -4.4f, 4e-20f };
os.write(orig);
os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
float[] uncompressed = new float[orig.length];
is.read(uncompressed);
is.close();
assertArrayEquals(orig, uncompressed, 0.0f);
}
@Test
public void writeIntArray() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b);
int[] orig = new int[] { 0, -1, -34, 43, 234, 34324, -234 };
os.write(orig);
os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
int[] uncompressed = new int[orig.length];
is.read(uncompressed);
is.close();
assertArrayEquals(orig, uncompressed);
}
@Test
public void writeShortArray() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b);
short[] orig = new short[] { 0, -1, -34, 43, 234, 324, -234 };
os.write(orig);
os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
short[] uncompressed = new short[orig.length];
is.read(uncompressed);
is.close();
assertArrayEquals(orig, uncompressed);
}
}

View File

@ -0,0 +1,50 @@
package org.xerial.snappy
import java.io.{ByteArrayOutputStream, ByteArrayInputStream}
import xerial.core.log.LogLevel
import scala.util.Random
/**
*
*/
class SnappyPerformanceTest extends SnappySpec {
lazy val data = {
val a = new Array[Byte](128 * 1024 * 1024)
for (i <- (0 until a.length).par) {
a(i) = Math.sin(i * 0.01).toByte
}
a
}
"SnappyOutputStream" should {
"improve output performance" taggedAs("out") in {
val input = data
time("compression", repeat=100, logLevel = LogLevel.INFO) {
// 0.037 sec. => 0.026
block("default") {
val out = new ByteArrayOutputStream()
val sout = new SnappyOutputStream(out)
sout.write(input)
sout.close()
out.close()
}
}
//info(f"compressed size: ${compressed.length}%,d, input: ${data.length}%,d")
}
}
}

View File

@ -0,0 +1,22 @@
package org.xerial.snappy
import org.scalatest._
import xerial.core.log.Logger
import xerial.core.util.Timer
/**
*
*/
trait SnappySpec
extends WordSpec
with Matchers
with GivenWhenThen
with OptionValues
with BeforeAndAfter
with Timer
with Logger
{
implicit def toTag(s:String) : Tag = Tag(s)
}

View File

@ -1 +1 @@
version in ThisBuild := "1.1.1"
version in ThisBuild := "1.1.2-SNAPSHOT"