Skip to content

Commit

Permalink
Transfer pre-serialized objects
Browse files Browse the repository at this point in the history
  • Loading branch information
apangin committed Sep 4, 2019
1 parent 8672aec commit 8197553
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/one/nio/serial/DataStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import one.nio.mem.DirectMemory;
import one.nio.util.Utf8;

import java.io.Closeable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
Expand Down Expand Up @@ -332,6 +333,10 @@ public void register(Object obj) {
// Nothing to do
}

public Closeable newScope() {
return null;
}

protected long alloc(int size) throws IOException {
long currentOffset = offset;
if ((offset = currentOffset + size) > limit) {
Expand Down
20 changes: 20 additions & 0 deletions src/one/nio/serial/DeserializeStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package one.nio.serial;

import java.io.Closeable;
import java.io.IOException;
import java.util.Arrays;

Expand Down Expand Up @@ -81,4 +82,23 @@ public void close() {
public void register(Object obj) {
context[contextSize] = obj;
}

@Override
public Closeable newScope() {
return new Closeable() {
private final Object[] prevContext = context;
private final int prevContextSize = contextSize;

{
context = new Object[INITIAL_CAPACITY];
contextSize = 0;
}

@Override
public void close() {
context = prevContext;
contextSize = prevContextSize;
}
};
}
}
5 changes: 5 additions & 0 deletions src/one/nio/serial/Repository.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ public class Repository {
addBootstrap(new RemoteCallSerializer());
addBootstrap(new SerializerSerializer(MethodSerializer.class));
addBootstrap(new HttpRequestSerializer());
addBootstrap(new SerializedWrapperSerializer());

classMap.put(int.class, classMap.get(Integer.class));
classMap.put(long.class, classMap.get(Long.class));
Expand Down Expand Up @@ -356,6 +357,10 @@ private static Serializer generateFor(Class<?> cls) {
} else {
serializer = new ExternalizableSerializer(cls);
}
} else if (SerializedWrapper.class.isAssignableFrom(cls)) {
serializer = classMap.get(SerializedWrapper.class);
classMap.put(cls, serializer);
return serializer;
} else if (Collection.class.isAssignableFrom(cls) && !hasOptions(cls, FIELD_SERIALIZATION)) {
serializer = new CollectionSerializer(cls);
} else if (Map.class.isAssignableFrom(cls) && !hasOptions(cls, FIELD_SERIALIZATION)) {
Expand Down
2 changes: 1 addition & 1 deletion src/one/nio/serial/SerializationContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import java.util.Arrays;

class SerializationContext {
public class SerializationContext {
private static final int INITIAL_CAPACITY = 64;

private Object first;
Expand Down
17 changes: 17 additions & 0 deletions src/one/nio/serial/SerializeStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package one.nio.serial;

import java.io.Closeable;
import java.io.IOException;

public class SerializeStream extends DataStream {
Expand Down Expand Up @@ -60,4 +61,20 @@ public void writeObject(Object obj) throws IOException {
public void close() {
context = null;
}

@Override
public Closeable newScope() {
return new Closeable() {
private final SerializationContext prevContext = context;

{
context = new SerializationContext();
}

@Override
public void close() {
context = prevContext;
}
};
}
}
62 changes: 62 additions & 0 deletions src/one/nio/serial/SerializedWrapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2019 Odnoklassniki Ltd, Mail.Ru Group
*
* 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 one.nio.serial;

import one.nio.util.Hash;

import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;

/**
* A wrapper for a preserialized object. Helps to avoid double serialization.
* The wrapper automatically unpacks the original object during deserialization.
*/
public class SerializedWrapper<T> implements Serializable {
private final byte[] serialized;

public SerializedWrapper(byte[] serialized) {
this.serialized = serialized;
}

public byte[] getSerialized() {
return serialized;
}

@Override
public int hashCode() {
return Hash.xxhash(serialized, 0, serialized.length);
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof SerializedWrapper)) {
return false;
}

return Arrays.equals(serialized, ((SerializedWrapper) obj).serialized);
}

public static <T> SerializedWrapper<T> wrap(T object) throws IOException {
return new SerializedWrapper<>(Serializer.serialize(object));
}

@SuppressWarnings("unchecked")
public T unwrap() throws IOException, ClassNotFoundException {
return (T) Serializer.deserialize(serialized);
}
}
72 changes: 72 additions & 0 deletions src/one/nio/serial/SerializedWrapperSerializer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2019 Odnoklassniki Ltd, Mail.Ru Group
*
* 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 one.nio.serial;

import java.io.Closeable;
import java.io.IOException;

/**
* Asymmetric serializer that writes a preserialized object as byte[],
* but reads an original object
*/
class SerializedWrapperSerializer extends Serializer<Object> {

SerializedWrapperSerializer() {
super(SerializedWrapper.class);
}

@Override
public void calcSize(Object obj, CalcSizeStream css) throws IOException {
css.add(getSerialized(obj).length);
}

@Override
public void write(Object obj, DataStream out) throws IOException {
out.write(getSerialized(obj));
}

@Override
public Object read(DataStream in) throws IOException, ClassNotFoundException {
Object result;
try (Closeable blankScope = in.newScope()) {
result = in.readObject();
}
in.register(result);
return result;
}

@Override
public void skip(DataStream in) throws IOException, ClassNotFoundException {
try (Closeable blankScope = in.newScope()) {
in.readObject();
}
}

@Override
public void toJson(Object obj, StringBuilder builder) throws IOException {
Json.appendBinary(builder, getSerialized(obj));
}

@Override
public Object fromJson(JsonReader in) throws IOException, ClassNotFoundException {
return Serializer.deserialize(in.readBinary());
}

private static byte[] getSerialized(Object obj) {
return ((SerializedWrapper) obj).getSerialized();
}
}
39 changes: 39 additions & 0 deletions test/one/nio/serial/SerializationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;

public class SerializationTest {
Expand Down Expand Up @@ -434,4 +437,40 @@ public void testHierarchy() throws IOException, ClassNotFoundException {
public void testChatSample() throws IOException, ClassNotFoundException {
checkSerialize(Sample.createChat());
}

static class MySerializedWrapper extends SerializedWrapper {

public MySerializedWrapper(byte[] serialized) {
super(serialized);
}

public static MySerializedWrapper wrap(Object obj) throws IOException {
return new MySerializedWrapper(Serializer.serialize(obj));
}
}

@Test
public void testSerializedWrapper() throws IOException, ClassNotFoundException {
Object original = Sample.createChat();

SerializedWrapper wrapper1 = SerializedWrapper.wrap(original);
MySerializedWrapper wrapper2 = MySerializedWrapper.wrap(original);
assertEquals(wrapper1, wrapper2);
assertEquals(wrapper1.hashCode(), wrapper2.hashCode());

byte[] serializedOriginal = Serializer.serialize(original);
byte[] serializedWrapper = Serializer.serialize(wrapper2);
assertEquals(serializedOriginal.length + 1, serializedWrapper.length);
assertArrayEquals(serializedOriginal, Arrays.copyOfRange(serializedWrapper, 1, serializedWrapper.length));

Object deserialized = clone(wrapper1);
assertEquals(original, deserialized);

Object[] array = {original, wrapper1, original, wrapper2};
Object[] deserializedArray = (Object[]) clone(array);
assertSame(deserializedArray[0], deserializedArray[2]);
assertNotSame(deserializedArray[1], deserializedArray[3]);
assertEquals(deserializedArray[0], deserializedArray[1]);
assertEquals(deserializedArray[0], deserializedArray[3]);
}
}

0 comments on commit 8197553

Please sign in to comment.