From 3e178dabf3574a17e26a710b23690555028ef2c9 Mon Sep 17 00:00:00 2001 From: Peter Taoussanis Date: Sun, 20 Jan 2013 16:53:29 +0700 Subject: [PATCH] EXPERIMENTAL: Swap Snappy implementation org.xerial.snappy/snappy-java -> org.iq80.snappy/snappy This (native Java) implementation appears to be about as fast as the old (JNI) implementation, but has better support across more platforms. Going to evaluate stability on this branch for possible later merging into master. --- project.clj | 4 ++-- src/taoensso/nippy.clj | 5 ++--- src/taoensso/nippy/benchmarks.clj | 6 ++++++ src/taoensso/nippy/utils.clj | 16 ++++++++++++++-- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/project.clj b/project.clj index cd0911a..09184ed 100644 --- a/project.clj +++ b/project.clj @@ -2,8 +2,8 @@ :description "Clojure serialization library" :url "https://github.com/ptaoussanis/nippy" :license {:name "Eclipse Public License"} - :dependencies [[org.clojure/clojure "1.3.0"] - [org.xerial.snappy/snappy-java "1.0.5-M3"]] + :dependencies [[org.clojure/clojure "1.3.0"] + [org.iq80.snappy/snappy "0.2"]] :profiles {:1.3 {:dependencies [[org.clojure/clojure "1.3.0"]]} :1.4 {:dependencies [[org.clojure/clojure "1.4.0"]]} :1.5 {:dependencies [[org.clojure/clojure "1.5.0-alpha3"]]} diff --git a/src/taoensso/nippy.clj b/src/taoensso/nippy.clj index 5f17d41..16b7fb0 100644 --- a/src/taoensso/nippy.clj +++ b/src/taoensso/nippy.clj @@ -5,7 +5,6 @@ (:require [taoensso.nippy.utils :as utils]) (:import [java.io DataInputStream DataOutputStream ByteArrayOutputStream ByteArrayInputStream] - [org.xerial.snappy Snappy] [clojure.lang IPersistentList IPersistentVector IPersistentMap IPersistentSet PersistentQueue IPersistentCollection Keyword BigInt Ratio])) @@ -165,7 +164,7 @@ stream (DataOutputStream. ba)] (freeze-to-stream! stream x print-dup?) (let [ba (.toByteArray ba)] - (if compress? (Snappy/compress ba) ba)))) + (if compress? (utils/compress-bytes ba) ba)))) ;;;; Thawing @@ -243,7 +242,7 @@ [ba & {:keys [read-eval? compressed?] :or {read-eval? false ; For `read-string` injection safety - NB!!! compressed? true}}] - (-> (if compressed? (Snappy/uncompress ba) ba) + (-> (if compressed? (utils/uncompress-bytes ba) ba) (ByteArrayInputStream.) (DataInputStream.) (thaw-from-stream! read-eval?))) diff --git a/src/taoensso/nippy/benchmarks.clj b/src/taoensso/nippy/benchmarks.clj index eeed80a..dcc6758 100644 --- a/src/taoensso/nippy/benchmarks.clj +++ b/src/taoensso/nippy/benchmarks.clj @@ -45,4 +45,10 @@ (let [frozen (reader-freeze data)] (count (.getBytes frozen "UTF8"))) (let [frozen (freeze-to-bytes data)] (count frozen)) ;; 22788, 12224 + + ;;; Snappy implementations + (println (bench (roundtrip data))) + ;; No Snappy: 6163 6064 6042 6176 + ;; Snappy JNI: 6489 6446 6542 6412 + ;; Snappy native array copy: 6569 6419 6414 6590 ) \ No newline at end of file diff --git a/src/taoensso/nippy/utils.clj b/src/taoensso/nippy/utils.clj index 17be404..7df1b64 100644 --- a/src/taoensso/nippy/utils.clj +++ b/src/taoensso/nippy/utils.clj @@ -1,6 +1,7 @@ (ns taoensso.nippy.utils {:author "Peter Taoussanis"} - (:require [clojure.string :as str])) + (:require [clojure.string :as str]) + (:import org.iq80.snappy.Snappy)) (defmacro case-eval "Like `case` but evaluates test constants for their compile-time value." @@ -55,4 +56,15 @@ (defn version-sufficient? [version-str min-version-str] (try (>= (version-compare version-str min-version-str) 0) - (catch Exception _ false))) \ No newline at end of file + (catch Exception _ false))) + +;; TODO Unnecessarily complicated. Waiting on http://goo.gl/7mbR3 merge. +(defn compress-bytes [ba] + (let [ba-size (alength ^bytes ba) + ba-out (byte-array (Snappy/maxCompressedLength ba-size)) + ba-out-size (Snappy/compress ba (int 0) (int ba-size) ba-out (int 0))] + (java.util.Arrays/copyOf ba-out ba-out-size))) + +(defn uncompress-bytes [ba] (Snappy/uncompress ba 0 (alength ^bytes ba))) + +(comment (String. (uncompress-bytes (compress-bytes (.getBytes "Test"))))) \ No newline at end of file