Skip to content

Commit

Permalink
Merge branch 'release/0.6.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Joe Nievelt committed May 12, 2015
2 parents 8f8843a + a0406b6 commit 476c70e
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 23 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# chill #

### 0.6.0 ###
* Add build instructions to readme and make InjectiveSerializer serializable #216
* Build chill-scrooge for scala 2.11, too #219
* Rewrite Java BitSet serializer to make it more efficient #220
* Bijection 0.8.0, algebird 0.10.0, scala 2.10.5 #228

### 0.5.2 ###
* Use new Travis CI infrastructure #210
* Optimizations for ConfiguredInstantiator. #213
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ Extensions for the [Kryo serialization library](https://github.com/EsotericSoftw
serializers and a set of classes to ease configuration of Kryo in systems like Hadoop, Storm,
Akka, etc.


### Buidling Chill

```bash
./sbt
> compile # to build chill
> publishM2 # to publish chill to your local .m2 repo
> publish-local # publish to local ivy repo.
```

Chill has a set of subprojects: chill-java, chill-hadoop, chill-storm and chill-scala. Other than
chill-scala, all these projects are written in Java so they are easy to use on any JVM platform.

Expand Down Expand Up @@ -149,7 +159,7 @@ Discussion occurs primarily on the [Chill mailing list](https://groups.google.co

## Maven

Chill modules are available on Maven Central. The current groupid and version for all modules is, respectively, `"com.twitter"` and `0.5.2` and each scala project is published for `2.10` and `2.11`. Search [search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Cchill) when in doubt.
Chill modules are available on Maven Central. The current groupid and version for all modules is, respectively, `"com.twitter"` and `0.6.0` and each scala project is published for `2.10` and `2.11`. Search [search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Cchill) when in doubt.

## Authors

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.twitter.chill

import _root_.java.io.Serializable

import com.twitter.bijection.Injection

/**
Expand All @@ -17,7 +19,7 @@ object InjectiveSerializer {
new InjectiveSerializer(injection)
}

class InjectiveSerializer[T] private (injection: Injection[T, Array[Byte]]) extends KSerializer[T] {
class InjectiveSerializer[T] private (injection: Injection[T, Array[Byte]]) extends KSerializer[T] with Serializable {
def write(kser: Kryo, out: Output, obj: T) {
val bytes = injection(obj)
out.writeInt(bytes.length, true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,88 @@
package com.twitter.chill.java;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

import com.twitter.chill.IKryoRegistrar;
import com.twitter.chill.SingleRegistrar;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.BitSet;

public class BitSetSerializer extends Serializer<BitSet> {
public class BitSetSerializer extends Serializer<BitSet> implements Serializable {

static public IKryoRegistrar registrar() {
return new SingleRegistrar(BitSet.class, new BitSetSerializer());
}

private final static Field wordsField;
private final static Constructor<BitSet> bitSetConstructor;
private final static Method recalculateWordsInUseMethod;

static {
try {
wordsField = BitSet.class.getDeclaredField("words");
wordsField.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new KryoException("Error while getting field 'words' of bitSet", e);
}
try {
bitSetConstructor = BitSet.class.getDeclaredConstructor(long[].class);
bitSetConstructor.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new KryoException("Unable to get BitSet(long[]) constructor", e);
}
try {
recalculateWordsInUseMethod = BitSet.class.getDeclaredMethod("recalculateWordsInUse");
recalculateWordsInUseMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new KryoException("Unable to get BitSet.recalculateWordsInUse() method", e);
}
}

@Override
public void write(Kryo kryo, Output output, BitSet bitSet) {
int len = bitSet.length();

output.writeInt(len, true);
long words[] = null;
// its sufficent to get only the 'words' field because
// we can recompute the wordsInUse after deserialization
try {
words = (long[]) wordsField.get(bitSet);
} catch (IllegalAccessException e) {
throw new KryoException("Error while accessing field 'words' of bitSet", e);
}
output.writeInt(words.length, true);

for(int i = 0; i < len; i++) {
output.writeBoolean(bitSet.get(i));
for(int i = 0; i < words.length; i++) {
output.writeLong(words[i]);
}
}

@Override
public BitSet read(Kryo kryo, Input input, Class<BitSet> bitSetClass) {
int len = input.readInt(true);
BitSet ret = new BitSet(len);
long[] target = new long[len];

for(int i = 0; i < len; i++) {
ret.set(i, input.readBoolean());
target[i] = input.readLong();
}

BitSet ret = null;
// call a private constructor: (the BitSet.valueOf() cTor is only available from Java 1.7)
try {
ret = bitSetConstructor.newInstance(target);
} catch (ReflectiveOperationException e) {
throw new KryoException("Unable to call BitSet(long[]) constructor", e);
}
try {
recalculateWordsInUseMethod.invoke(ret);
} catch (ReflectiveOperationException e) {
throw new KryoException("Unable to call BitSet.recalculateWordsInUse() method", e);
}

return ret;
Expand Down
111 changes: 111 additions & 0 deletions chill-java/src/test/scala/com/twitter/chill/java/BitSetTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.twitter.chill.java

import java.util

import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.io.{Input, Output}
import org.objenesis.strategy.StdInstantiatorStrategy
import org.scalatest._

import scala.util.Random

class BitSetSpec extends WordSpec with MustMatchers {

implicit val kryo = new Kryo()

def rt[A](a: A)(implicit k: Kryo): A = {
val out = new Output(1000, -1)
k.writeClassAndObject(out, a.asInstanceOf[AnyRef])
val in = new Input(out.toBytes)
k.readClassAndObject(in).asInstanceOf[A]
}

"A BitSetSerializer serializer" should {
"handle BitSet" in {
kryo.setInstantiatorStrategy(new StdInstantiatorStrategy)
BitSetSerializer.registrar()(kryo)
var simple = new util.BitSet(2048)
simple.size() must be(2048)
for (i <- 0 to 1337) {
simple.set(i, true)
}
// we assume everything after 1337 to be false
simple.get(1338) must equal(false)
simple.get(2000) must equal(false)
var dolly = rt(simple)
simple = null // avoid accidental calls
dolly.size() must be(2048)
for (i <- 0 to 1337) {
dolly.get(i) must be(true)
}
dolly.get(1338) must equal(false)
dolly.get(2000) must equal(false)
}

/**
* My results:
* The old serializer took 2886ms
* The new serializer took 112ms
* The old serializer needs 2051 bytes
* The new serializer needs 258 bytes
*/
"handle a BitSet efficiently" in {
val oldKryo = new Kryo()
OldBitSetSerializer.registrar()(oldKryo)

val newKryo = new Kryo()
BitSetSerializer.registrar()(newKryo)

val element = new util.BitSet(2048)
val rnd = new Random()
for (i <- 0 to 2048) {
element.set(i, rnd.nextBoolean())
}

// warmup In case anybody wants to see hotspot
var lastBitSetFromOld : util.BitSet = null
for(i <- 0 to 50000) {
lastBitSetFromOld = rt(element)(oldKryo)
}
var start = System.currentTimeMillis()
for(i <- 0 to 100000) {
rt(element)(oldKryo)
}
println("The old serializer took "+(System.currentTimeMillis() - start)+"ms")

var lastBitSetFromNew : util.BitSet = null
// warmup for the new kryo
for(i <- 0 to 50000) {
lastBitSetFromNew = rt(element)(newKryo)
}
// check for the three bitsets to be equal
for (i <- 0 to 2048) {
// original bitset against old serializer output
element.get(i) must be(lastBitSetFromOld.get(i))

// original bitset against new serializer output
element.get(i) must be(lastBitSetFromNew.get(i))
}


start = System.currentTimeMillis()
for(i <- 0 to 100000) {
rt(element)(newKryo)
}
println("The new serializer took "+(System.currentTimeMillis() - start)+"ms")

var out = new Output(1, -1)
oldKryo.writeObject(out, element)
out.flush()
var oldBytes = out.total()
println("The old serializer needs "+oldBytes+" bytes")
out = new Output(1, -1)
newKryo.writeObject(out, element)
out.flush()
var newBytes = out.total()
println("The new serializer needs "+newBytes+" bytes")

oldBytes >= newBytes must be(true)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ package com.twitter.chill.java

import org.scalatest._

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output

import org.objenesis.strategy.StdInstantiatorStrategy

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
Copyright 2013 Twitter, Inc.
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.
*/

package com.twitter.chill.java;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.twitter.chill.IKryoRegistrar;
import com.twitter.chill.SingleRegistrar;

import java.util.BitSet;

public class OldBitSetSerializer extends Serializer<BitSet> {

static public IKryoRegistrar registrar() {
return new SingleRegistrar(BitSet.class, new OldBitSetSerializer());
}

@Override
public void write(Kryo kryo, Output output, BitSet bitSet) {
int len = bitSet.length();

output.writeInt(len, true);

for(int i = 0; i < len; i++) {
output.writeBoolean(bitSet.get(i));
}
}

@Override
public BitSet read(Kryo kryo, Input input, Class<BitSet> bitSetClass) {
int len = input.readInt(true);
BitSet ret = new BitSet(len);

for(int i = 0; i < len; i++) {
ret.set(i, input.readBoolean());
}

return ret;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ package com.twitter.chill.java

import org.scalatest._

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output

import org.objenesis.strategy.StdInstantiatorStrategy

Expand Down
14 changes: 7 additions & 7 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ object ChillBuild extends Build {

val sharedSettings = Project.defaultSettings ++ mimaDefaultSettings ++ scalariformSettings ++ Seq(

version := "0.5.2",
version := "0.6.0",
organization := "com.twitter",
scalaVersion := "2.10.4",
crossScalaVersions := Seq("2.10.4", "2.11.5"),
scalaVersion := "2.10.5",
crossScalaVersions := Seq("2.10.5", "2.11.5"),
scalacOptions ++= Seq("-unchecked", "-deprecation"),
ScalariformKeys.preferences := formattingPreferences,

Expand Down Expand Up @@ -126,7 +126,7 @@ object ChillBuild extends Build {
.filterNot(unreleasedModules.contains(_))
.map { s =>
val suffix = if (javaOnly.contains(s)) "" else "_2.10"
"com.twitter" % ("chill-" + s + suffix) % "0.5.2"
"com.twitter" % ("chill-" + s + suffix) % "0.6.0"
}

def module(name: String) = {
Expand Down Expand Up @@ -158,7 +158,7 @@ object ChillBuild extends Build {

lazy val chillBijection = module("bijection").settings(
libraryDependencies ++= Seq(
"com.twitter" %% "bijection-core" % "0.7.2"
"com.twitter" %% "bijection-core" % "0.8.0"
)
).dependsOn(chill % "test->test;compile->compile")

Expand Down Expand Up @@ -217,14 +217,14 @@ object ChillBuild extends Build {

lazy val chillAvro = module("avro").settings(
libraryDependencies ++= Seq(
"com.twitter" %% "bijection-avro" % "0.7.2",
"com.twitter" %% "bijection-avro" % "0.8.0",
"junit" % "junit" % "4.5" % "test"
)
).dependsOn(chill,chillJava, chillBijection)

lazy val chillAlgebird = module("algebird").settings(
libraryDependencies ++= Seq(
"com.twitter" %% "algebird-core" % "0.9.0"
"com.twitter" %% "algebird-core" % "0.10.0"
)
).dependsOn(chill)
}

0 comments on commit 476c70e

Please sign in to comment.