Skip to content

Commit 0043573

Browse files
committed
Merge branch 'release/0.2.3'
2 parents 56acd2c + 65ef3bb commit 0043573

14 files changed

Lines changed: 220 additions & 49 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
/src/intellij/*.iws
2929
/.cache
3030
/.idea
31+
/.idea_modules
3132
/.settings
3233

3334
# bak files produced by ./cleanup-commit

CHANGES.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# chill #
22

3+
### 0.2.3
4+
* Update to Kryo 2.21
5+
* Update to Bijection 0.4.0
6+
* Improve Traversable Serializer
7+
8+
### 0.2.2
9+
10+
* Custom RegexSerializer
11+
* ArrayBuffer serialization fix (#48)
12+
313
### 0.2.1
414
* Improve MeatLocker (safe to call get before serialization)
515
* Fix a bug with serialization of mutable collections

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Chill provides support for singletons, scala Objects and the following types:
4444

4545
## Maven
4646

47-
Current version is `0.2.1 `. groupid=`"com.twitter"` artifact=`"chill_2.9.2"` or artifact=`"chill_2.10"`.
47+
Current version is `0.2.3`. groupid=`"com.twitter"` artifact=`"chill_2.9.2"` or artifact=`"chill_2.10"`.
4848

4949
## Authors
5050

chill-scala/src/main/scala/com/twitter/chill/InjectiveSerializer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class InjectiveSerializer[T] private (injection: Injection[T, Array[Byte]]) exte
2323
def write(kser: Kryo, out: Output, obj: T) {
2424
val bytes = injection(obj)
2525
out.writeInt(bytes.length, true)
26-
out.writeBytes(bytes);
26+
out.writeBytes(bytes)
2727
}
2828

2929
def read(kser: Kryo, in: Input, cls: Class[T]): T = {

chill-scala/src/main/scala/com/twitter/chill/KryoBase.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,19 @@ package com.twitter.chill
1919
import com.esotericsoftware.kryo.Kryo
2020
import com.esotericsoftware.kryo.KryoException
2121
import com.esotericsoftware.kryo.{ Serializer => KSerializer }
22-
import com.esotericsoftware.reflectasm.ConstructorAccess;
22+
import com.esotericsoftware.reflectasm.ConstructorAccess
2323
import com.esotericsoftware.kryo.serializers.FieldSerializer
2424

25-
import org.objenesis.instantiator.ObjectInstantiator;
26-
import org.objenesis.strategy.InstantiatorStrategy;
25+
import org.objenesis.instantiator.ObjectInstantiator
26+
import org.objenesis.strategy.InstantiatorStrategy
27+
28+
import java.lang.reflect.Constructor
29+
import java.lang.reflect.Modifier
2730

28-
import java.lang.reflect.Constructor;
29-
import java.lang.reflect.Modifier;
3031
/*
3132
* This is the base class of Kryo we use to fix specific scala
3233
* related issues discovered (ideally, this should be fixed in Kryo)
3334
*/
34-
3535
class KryoBase extends Kryo {
3636

3737
lazy val objSer = new ObjectSerializer[AnyRef]

chill-scala/src/main/scala/com/twitter/chill/KryoBijection.scala

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,43 @@ trait KryoBijection extends Bijection[AnyRef, Array[Byte]] {
5656
* TODO: Delete KryoBijection, use KryoInjection everywhere.
5757
*/
5858
object KryoInjection extends Injection[AnyRef, Array[Byte]] {
59-
override def apply(obj: AnyRef) = KryoBijection(obj)
60-
override def invert(bytes: Array[Byte]) = allCatch.opt(KryoBijection.invert(bytes))
59+
// Create a default injection to use, 4KB init, max 16 MB
60+
private val kinject = instance(init = 1 << 12, max = 1 << 24)
61+
62+
override def apply(obj: AnyRef) = kinject.synchronized { kinject(obj) }
63+
override def invert(bytes: Array[Byte]) = kinject.synchronized { kinject.invert(bytes) }
64+
65+
/**
66+
* Create a new KryoInjection instance that serializes items using
67+
* the supplied Kryo instance. The buffer used for serialization is
68+
* initialized, by default, to 1KB, with a max size of
69+
* 16MB. Configure these limits by passing in new values for "init"
70+
* and "max" respectively.
71+
*/
72+
def instance(
73+
kryo: Kryo = KryoBijection.getKryo,
74+
init: Int = 1 << 10,
75+
max: Int = 1 << 24
76+
): Injection[AnyRef, Array[Byte]] =
77+
new KryoInjectionInstance(kryo, new Output(init, max))
78+
}
79+
80+
/**
81+
* Reuse the Output and Kryo, which is faster
82+
* register any additional serializers you need before passing in the
83+
* Kryo instance
84+
*/
85+
class KryoInjectionInstance(kryo: Kryo, output: Output) extends Injection[AnyRef, Array[Byte]] {
86+
private val input: Input = new Input
87+
88+
def apply(obj: AnyRef): Array[Byte] = {
89+
output.clear
90+
kryo.writeClassAndObject(output, obj)
91+
output.toBytes
92+
}
93+
94+
def invert(b: Array[Byte]): Option[AnyRef] = {
95+
input.setBuffer(b)
96+
allCatch.opt(kryo.readClassAndObject(input))
97+
}
6198
}

chill-scala/src/main/scala/com/twitter/chill/KryoSerializer.scala

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ import com.esotericsoftware.kryo.Kryo
2020
import com.esotericsoftware.kryo.{ Serializer => KSerializer }
2121
import com.esotericsoftware.kryo.io.{ Input, Output }
2222

23-
import com.twitter.bijection.{ Base64String, Bufferable, ImplicitBijection, Injection }
24-
25-
import org.objenesis.strategy.StdInstantiatorStrategy
23+
import com.twitter.bijection.{ Bufferable, ImplicitBijection }
2624

2725
import scala.collection.immutable.{
2826
BitSet,
@@ -32,14 +30,14 @@ import scala.collection.immutable.{
3230
}
3331

3432
import scala.collection.mutable.{
35-
Builder,
3633
WrappedArray,
3734
Map => MMap,
3835
Set => MSet,
3936
ListBuffer,
4037
Queue => MQueue,
4138
Buffer
4239
}
40+
import scala.util.matching.Regex
4341

4442
object KryoSerializer {
4543

@@ -88,13 +86,17 @@ object KryoSerializer {
8886
* You should go from MOST specific, to least to specific when using
8987
* default serializers. The FIRST one found is the one used
9088
*/
91-
// wrapper array is abstract
92-
newK.forSubclass[WrappedArray[Any]](new WrappedArraySerializer[Any])
89+
newK
90+
.forSubclass[Regex](new RegexSerializer)
91+
// wrapper array is abstract
92+
.forSubclass[WrappedArray[Any]](new WrappedArraySerializer[Any])
9393
.forSubclass[BitSet](new BitSetSerializer)
9494
.forSubclass[java.util.PriorityQueue[AnyRef]](new PriorityQueueSerializer[AnyRef])
9595
.forTraversableSubclass(Queue.newBuilder[Any])
9696
// List is a sealed class, so there are only two subclasses:
9797
.forTraversableSubclass(List.newBuilder[Any])
98+
// add mutable Buffer before Vector, otherwise Vector is used
99+
.forTraversableSubclass(Buffer.newBuilder[Any], isImmutable = false)
98100
//Vector is a final class
99101
.forTraversableClass(Vector.newBuilder[Any])
100102
.forTraversableSubclass(IndexedSeq.newBuilder[Any])
@@ -109,7 +111,6 @@ object KryoSerializer {
109111
.forTraversableSubclass(MMap.newBuilder[Any,Any], isImmutable = false)
110112
.forTraversableSubclass(MSet.newBuilder[Any], isImmutable = false)
111113
.forTraversableSubclass(ListBuffer.newBuilder[Any], isImmutable = false)
112-
.forTraversableSubclass(Buffer.newBuilder[Any], isImmutable = false)
113114
// This should be last, lots of things are seq/iterable/traversable
114115
// These are questionable and might break things.
115116
// rarely will you only expect an iterable/traversable on the reverse
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
Copyright 2012 Twitter, Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package com.twitter.chill
18+
19+
import com.esotericsoftware.kryo.Kryo
20+
import com.esotericsoftware.kryo.{ Serializer => KSerializer }
21+
import com.esotericsoftware.kryo.io.{ Input, Output }
22+
import scala.util.matching.Regex
23+
24+
class RegexSerializer extends KSerializer[Regex] {
25+
def write(kser: Kryo, out: Output, obj: Regex) {
26+
out.writeString(obj.pattern.pattern)
27+
}
28+
29+
def read(kser: Kryo, in: Input, cls: Class[Regex]): Regex = {
30+
new Regex(in.readString)
31+
}
32+
}

chill-scala/src/main/scala/com/twitter/chill/RichKryo.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import com.esotericsoftware.kryo.Kryo
2020
import com.esotericsoftware.kryo.{ Serializer => KSerializer }
2121
import com.esotericsoftware.kryo.io.{ Input, Output }
2222

23-
import com.twitter.bijection.{ Bufferable, ImplicitBijection, Injection }
23+
import com.twitter.bijection.{ Bufferable, Bijection, ImplicitBijection, Injection }
2424

2525
import scala.collection.mutable.Builder
2626

@@ -100,6 +100,12 @@ class RichKryo(k: Kryo) {
100100
k
101101
}
102102

103+
/** Helpful override to alleviate rewriting types. */
104+
def forClassViaBijection[A,B](bij: Bijection[A,B])(implicit acmf: ClassManifest[A], bcmf: ClassManifest[B]): Kryo = {
105+
implicit def implicitBij = bij
106+
this.forClassViaBijection[A, B]
107+
}
108+
103109
/** Use Java serialization, which is very slow.
104110
* avoid this if possible, but for very rare classes it is probably fine
105111
*/

chill-scala/src/main/scala/com/twitter/chill/Traversable.scala

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ class TraversableSerializer[T, C <: Traversable[T]](builder: Builder[T, C],
2626
override val isImmutable: Boolean = true)
2727
extends KSerializer[C] {
2828

29+
sealed trait Finisher {
30+
def apply(in: C): C
31+
}
32+
case object Clone extends Finisher {
33+
def apply(in: C) = in.asInstanceOf[Cloneable[C]].clone
34+
}
35+
case object Pass extends Finisher {
36+
def apply(in: C) = in
37+
}
38+
39+
var finisher: Option[Finisher] = None
40+
2941
def write(kser: Kryo, out: Output, obj: C) {
3042
//Write the size:
3143
out.writeInt(obj.size, true)
@@ -52,11 +64,16 @@ class TraversableSerializer[T, C <: Traversable[T]](builder: Builder[T, C],
5264

5365
// TODO remove this and use CanBuildFrom from rather than Builder
5466
// when we bump major versions
55-
protected def copyIfMutable(c: C): C = c match {
56-
case m: scala.Mutable => m match {
57-
case toclone: Cloneable[C] => toclone.clone
58-
case _ => throw new Exception("Cannot use TraversableSerializer with non-clonable mutables")
59-
}
60-
case _ => c
61-
}
67+
protected def copyIfMutable(c: C): C = finisher.getOrElse {
68+
val fin = c match {
69+
case m: scala.Mutable => m match {
70+
case toclone: Cloneable[C] => Clone
71+
case _ => throw new Exception("Cannot use TraversableSerializer with non-clonable mutables")
72+
}
73+
case _ => Pass
74+
}
75+
// Cache this for next time
76+
finisher = Some(fin)
77+
fin
78+
}.apply(c)
6279
}

0 commit comments

Comments
 (0)