You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ds...@apache.org on 2017/03/07 19:21:53 UTC

[30/51] [abbrv] geode git commit: GEODE-2538: Don't deserialize values on the server when getting results

GEODE-2538: Don't deserialize values on the server when getting results

If values on the server are in serialized form, leave them that way and
only deserialize the values on the clients.

This is implemented by having the LuceneGetPageFunction extract the
serialized value and return the results in a new PageResults class,
which handles the deserialization and upwrapping of the value if
necessary.


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/8b762bed
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/8b762bed
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/8b762bed

Branch: refs/heads/feature/GEM-1195
Commit: 8b762bede8e064704ea67ba986491184066c2b56
Parents: b5cbaed
Author: Dan Smith <up...@apache.org>
Authored: Mon Feb 27 18:03:18 2017 -0800
Committer: Dan Smith <up...@apache.org>
Committed: Tue Feb 28 17:41:04 2017 -0800

----------------------------------------------------------------------
 .../geode/internal/DataSerializableFixedID.java |  1 +
 .../lucene/internal/LuceneServiceImpl.java      |  3 +
 .../internal/results/LuceneGetPageFunction.java | 55 +++++------
 .../internal/results/MapResultCollector.java    | 11 ++-
 .../lucene/internal/results/PageEntry.java      | 98 ++++++++++++++++++++
 .../lucene/internal/results/PageResults.java    | 60 ++++++++++++
 .../results/LuceneGetPageFunctionJUnitTest.java | 12 ++-
 .../internal/results/PageEntryJUnitTest.java    | 93 +++++++++++++++++++
 .../internal/results/PageResultsJUnitTest.java  | 44 +++++++++
 9 files changed, 336 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/8b762bed/geode-core/src/main/java/org/apache/geode/internal/DataSerializableFixedID.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/DataSerializableFixedID.java b/geode-core/src/main/java/org/apache/geode/internal/DataSerializableFixedID.java
index 457af2f..63a95a5 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/DataSerializableFixedID.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/DataSerializableFixedID.java
@@ -810,6 +810,7 @@ public interface DataSerializableFixedID extends SerializationVersions {
   public static final short LUCENE_TOP_ENTRIES_COLLECTOR = 2176;
   public static final short WAIT_UNTIL_FLUSHED_FUNCTION_CONTEXT = 2177;
   public static final short DESTROY_LUCENE_INDEX_MESSAGE = 2178;
+  public static final short LUCENE_PAGE_RESULTS = 2179;
 
   // NOTE, codes > 65535 will take 4 bytes to serialize
 

http://git-wip-us.apache.org/repos/asf/geode/blob/8b762bed/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java
----------------------------------------------------------------------
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java
index dd32000..a1a6ef3 100644
--- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java
+++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java
@@ -22,6 +22,7 @@ import org.apache.geode.cache.lucene.internal.distributed.LuceneQueryFunction;
 import org.apache.geode.cache.lucene.internal.management.LuceneServiceMBean;
 import org.apache.geode.cache.lucene.internal.management.ManagementIndexListener;
 import org.apache.geode.cache.lucene.internal.results.LuceneGetPageFunction;
+import org.apache.geode.cache.lucene.internal.results.PageResults;
 import org.apache.geode.management.internal.beans.CacheServiceMBeanBase;
 import org.apache.logging.log4j.Logger;
 import org.apache.lucene.analysis.Analyzer;
@@ -373,6 +374,8 @@ public class LuceneServiceImpl implements InternalLuceneService {
 
     DSFIDFactory.registerDSFID(DataSerializableFixedID.DESTROY_LUCENE_INDEX_MESSAGE,
         DestroyLuceneIndexMessage.class);
+
+    DSFIDFactory.registerDSFID(DataSerializableFixedID.LUCENE_PAGE_RESULTS, PageResults.class);
   }
 
   public Collection<LuceneIndexCreationProfile> getAllDefinedIndexes() {

http://git-wip-us.apache.org/repos/asf/geode/blob/8b762bed/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/LuceneGetPageFunction.java
----------------------------------------------------------------------
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/LuceneGetPageFunction.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/LuceneGetPageFunction.java
index f5c2b99..0addf48 100644
--- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/LuceneGetPageFunction.java
+++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/LuceneGetPageFunction.java
@@ -15,40 +15,18 @@
 
 package org.apache.geode.cache.lucene.internal.results;
 
-import org.apache.geode.cache.EntryDestroyedException;
 import org.apache.geode.cache.Region;
-import org.apache.geode.cache.Region.Entry;
 import org.apache.geode.cache.execute.Function;
 import org.apache.geode.cache.execute.FunctionContext;
-import org.apache.geode.cache.execute.FunctionException;
 import org.apache.geode.cache.execute.RegionFunctionContext;
-import org.apache.geode.cache.execute.ResultSender;
-import org.apache.geode.cache.lucene.LuceneQueryException;
-import org.apache.geode.cache.lucene.LuceneQueryProvider;
-import org.apache.geode.cache.lucene.LuceneService;
-import org.apache.geode.cache.lucene.LuceneServiceProvider;
-import org.apache.geode.cache.lucene.internal.LuceneIndexImpl;
-import org.apache.geode.cache.lucene.internal.LuceneIndexStats;
-import org.apache.geode.cache.lucene.internal.distributed.CollectorManager;
-import org.apache.geode.cache.lucene.internal.distributed.LuceneFunctionContext;
-import org.apache.geode.cache.lucene.internal.distributed.TopEntriesCollector;
-import org.apache.geode.cache.lucene.internal.distributed.TopEntriesCollectorManager;
-import org.apache.geode.cache.lucene.internal.repository.IndexRepository;
-import org.apache.geode.cache.lucene.internal.repository.IndexResultCollector;
-import org.apache.geode.cache.lucene.internal.repository.RepositoryManager;
 import org.apache.geode.cache.partition.PartitionRegionHelper;
 import org.apache.geode.internal.InternalEntity;
-import org.apache.geode.internal.cache.BucketNotFoundException;
-import org.apache.geode.internal.cache.execute.InternalFunctionInvocationTargetException;
+import org.apache.geode.internal.cache.EntrySnapshot;
+import org.apache.geode.internal.cache.Token;
 import org.apache.geode.internal.logging.LogService;
 import org.apache.logging.log4j.Logger;
-import org.apache.lucene.search.Query;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -67,22 +45,31 @@ public class LuceneGetPageFunction implements Function, InternalEntity {
     Region region = PartitionRegionHelper.getLocalDataForContext(ctx);
     Set<?> keys = ctx.getFilter();
 
-    Map<Object, Object> results = new HashMap<>(keys.size());
+    List<PageEntry> results = new PageResults(keys.size());
 
     for (Object key : keys) {
-      final Entry entry = region.getEntry(key);
-      try {
-        Object value = entry == null ? null : entry.getValue();
-        if (value != null) {
-          results.put(key, value);
-        }
-      } catch (EntryDestroyedException e) {
-        // skip
+      PageEntry entry = getEntry(region, key);
+      if (entry != null) {
+        results.add(entry);
       }
     }
     ctx.getResultSender().lastResult(results);
   }
 
+  protected PageEntry getEntry(final Region region, final Object key) {
+    final EntrySnapshot entry = (EntrySnapshot) region.getEntry(key);
+    if (entry == null) {
+      return null;
+    }
+
+    final Object value = entry.getRegionEntry().getValue(null);
+    if (value == null || Token.isInvalidOrRemoved(value)) {
+      return null;
+    }
+
+    return new PageEntry(key, value);
+  }
+
 
   @Override
   public String getId() {

http://git-wip-us.apache.org/repos/asf/geode/blob/8b762bed/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/MapResultCollector.java
----------------------------------------------------------------------
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/MapResultCollector.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/MapResultCollector.java
index 9264126..0a9b110 100644
--- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/MapResultCollector.java
+++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/MapResultCollector.java
@@ -19,10 +19,11 @@ import org.apache.geode.cache.execute.ResultCollector;
 import org.apache.geode.distributed.DistributedMember;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
-public class MapResultCollector implements ResultCollector<Map<?, ?>, Map<Object, Object>> {
+public class MapResultCollector implements ResultCollector<List<PageEntry>, Map<Object, Object>> {
   private final Map<Object, Object> results = new HashMap<>();
 
   @Override
@@ -37,9 +38,11 @@ public class MapResultCollector implements ResultCollector<Map<?, ?>, Map<Object
   }
 
   @Override
-  public void addResult(final DistributedMember memberID, final Map<?, ?> resultOfSingleExecution) {
-    this.results.putAll(resultOfSingleExecution);
-
+  public void addResult(final DistributedMember memberID,
+      final List<PageEntry> resultOfSingleExecution) {
+    for (PageEntry entry : resultOfSingleExecution) {
+      results.put(entry.getKey(), entry.getValue());
+    }
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/geode/blob/8b762bed/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/PageEntry.java
----------------------------------------------------------------------
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/PageEntry.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/PageEntry.java
new file mode 100644
index 0000000..1f52c2e
--- /dev/null
+++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/PageEntry.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.cache.lucene.internal.results;
+
+import org.apache.geode.DataSerializable;
+import org.apache.geode.DataSerializer;
+import org.apache.geode.internal.cache.CachedDeserializable;
+import org.apache.geode.internal.offheap.StoredObject;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+public class PageEntry {
+
+  public Object key;
+  public Object value;
+
+  public PageEntry() {}
+
+  public PageEntry(final Object key, final Object value) {
+    this.key = key;
+    this.value = value;
+  }
+
+  public Object getKey() {
+    return key;
+  }
+
+  public Object getValue() {
+    if (value instanceof CachedDeserializable) {
+      return ((CachedDeserializable) value).getDeserializedValue(null, null);
+    }
+
+    return value;
+  }
+
+  public void toData(final DataOutput out) throws IOException {
+
+    DataSerializer.writeObject(key, out);
+    if (value instanceof StoredObject) {
+      ((StoredObject) value).sendTo(out);
+      return;
+    }
+
+    if (value instanceof CachedDeserializable) {
+      value = ((CachedDeserializable) value).getValue();
+      if (value instanceof byte[]) {
+        out.write((byte[]) value);
+        return;
+      }
+    }
+
+    DataSerializer.writeObject(value, out);
+  }
+
+  public void fromData(final DataInput in) throws IOException, ClassNotFoundException {
+    key = DataSerializer.readObject(in);
+    value = DataSerializer.readObject(in);
+  }
+
+  @Override
+  public boolean equals(final Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+
+    final PageEntry pageEntry = (PageEntry) o;
+
+    if (!getKey().equals(pageEntry.getKey())) {
+      return false;
+    }
+    return getValue().equals(pageEntry.getValue());
+
+  }
+
+  @Override
+  public int hashCode() {
+    int result = getKey().hashCode();
+    result = 31 * result + getValue().hashCode();
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/8b762bed/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/PageResults.java
----------------------------------------------------------------------
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/PageResults.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/PageResults.java
new file mode 100644
index 0000000..fcacff2
--- /dev/null
+++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/results/PageResults.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.cache.lucene.internal.results;
+
+import org.apache.geode.internal.DataSerializableFixedID;
+import org.apache.geode.internal.Version;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class PageResults extends ArrayList<PageEntry> implements DataSerializableFixedID {
+
+  public PageResults(final int initialCapacity) {
+    super(initialCapacity);
+  }
+
+  public PageResults() {}
+
+  @Override
+  public int getDSFID() {
+    return DataSerializableFixedID.LUCENE_PAGE_RESULTS;
+  }
+
+  @Override
+  public void toData(final DataOutput out) throws IOException {
+    out.writeInt(this.size());
+    for (PageEntry entry : this) {
+      entry.toData(out);
+    }
+  }
+
+  @Override
+  public void fromData(final DataInput in) throws IOException, ClassNotFoundException {
+    int size = in.readInt();
+    for (int i = 0; i < size; i++) {
+      PageEntry entry = new PageEntry();
+      entry.fromData(in);
+      add(entry);
+    }
+  }
+
+  @Override
+  public Version[] getSerializationVersions() {
+    return new Version[0];
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/8b762bed/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/LuceneGetPageFunctionJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/LuceneGetPageFunctionJUnitTest.java b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/LuceneGetPageFunctionJUnitTest.java
index c62082c..5f1ca3f 100644
--- a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/LuceneGetPageFunctionJUnitTest.java
+++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/LuceneGetPageFunctionJUnitTest.java
@@ -26,7 +26,9 @@ import org.apache.geode.cache.Region.Entry;
 import org.apache.geode.cache.execute.FunctionContext;
 import org.apache.geode.cache.execute.RegionFunctionContext;
 import org.apache.geode.cache.execute.ResultSender;
+import org.apache.geode.internal.cache.EntrySnapshot;
 import org.apache.geode.internal.cache.PartitionedRegion;
+import org.apache.geode.internal.cache.RegionEntry;
 import org.apache.geode.internal.cache.execute.InternalRegionFunctionContext;
 import org.apache.geode.test.junit.categories.UnitTest;
 import org.junit.Test;
@@ -47,13 +49,17 @@ public class LuceneGetPageFunctionJUnitTest {
     when(context.getResultSender()).thenReturn(resultSender);
     LuceneGetPageFunction function = new LuceneGetPageFunction();
     when(context.getLocalDataSet(any())).thenReturn(region);
-    final Entry entry = mock(Entry.class);
+    final EntrySnapshot entry = mock(EntrySnapshot.class);
     when(region.getEntry(any())).thenReturn(entry);
-    when(entry.getValue()).thenReturn("value");
+    final RegionEntry regionEntry = mock(RegionEntry.class);
+    when(entry.getRegionEntry()).thenReturn(regionEntry);
+    when(regionEntry.getValue(any())).thenReturn("value");
     when(context.getFilter()).thenReturn((Set) Collections.singleton("key"));
     function.execute(context);
 
-    verify(resultSender).lastResult(eq(Collections.singletonMap("key", "value")));
+    PageResults expectedResults = new PageResults();
+    expectedResults.add(new PageEntry("key", "value"));
+    verify(resultSender).lastResult(eq(expectedResults));
   }
 
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/8b762bed/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/PageEntryJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/PageEntryJUnitTest.java b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/PageEntryJUnitTest.java
new file mode 100644
index 0000000..6e26942
--- /dev/null
+++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/PageEntryJUnitTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.cache.lucene.internal.results;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import org.apache.geode.internal.ByteArrayDataInput;
+import org.apache.geode.internal.HeapDataOutputStream;
+import org.apache.geode.internal.Version;
+import org.apache.geode.internal.cache.CachedDeserializable;
+import org.apache.geode.internal.cache.PreferBytesCachedDeserializable;
+import org.apache.geode.internal.util.BlobHelper;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+@Category(UnitTest.class)
+public class PageEntryJUnitTest {
+
+  @Test
+  public void getValueShouldReturnObjectValue() {
+    PageEntry entry = new PageEntry("key", "value");
+    assertEquals("value", entry.getValue());
+  }
+
+  @Test
+  public void getValueShouldReturnObjectFromCachedDeserializableValue() {
+    CachedDeserializable cachedDeserializable = new PreferBytesCachedDeserializable("value");
+    PageEntry entry = new PageEntry("key", cachedDeserializable);
+    assertEquals("value", entry.getValue());
+  }
+
+  @Test
+  public void getValueShouldReturnBytesFromBytesValue() {
+    byte[] bytes = new byte[10];
+    Arrays.fill(bytes, (byte) 5);
+    PageEntry entry = new PageEntry("key", bytes);
+    assertArrayEquals(bytes, (byte[]) entry.getValue());
+  }
+
+  @Test
+  public void serializationWithObjectValueShouldNotModifyValue()
+      throws IOException, ClassNotFoundException {
+    PageEntry entry = new PageEntry("key", "value");
+    assertEquals("value", copy(entry).getValue());
+  }
+
+  @Test
+  public void serializationReturnObjectFromCachedDeserializableValue()
+      throws IOException, ClassNotFoundException {
+    CachedDeserializable cachedDeserializable = new PreferBytesCachedDeserializable("value");
+    PageEntry entry = new PageEntry("key", cachedDeserializable);
+    assertEquals("value", copy(entry).getValue());
+  }
+
+  @Test
+  public void serializationShouldReturnsBytesFromByteValue()
+      throws IOException, ClassNotFoundException {
+    byte[] bytes = new byte[10];
+    Arrays.fill(bytes, (byte) 5);
+    PageEntry entry = new PageEntry("key", bytes);
+    assertArrayEquals(bytes, (byte[]) copy(entry).getValue());
+  }
+
+  public PageEntry copy(PageEntry entry) throws IOException, ClassNotFoundException {
+    HeapDataOutputStream out = new HeapDataOutputStream((Version) null);
+    entry.toData(out);
+    final byte[] bytes = out.toByteArray();
+    ByteArrayDataInput in = new ByteArrayDataInput();
+    in.initialize(bytes, null);
+    PageEntry newEntry = new PageEntry();
+    newEntry.fromData(in);
+    return newEntry;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/8b762bed/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/PageResultsJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/PageResultsJUnitTest.java b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/PageResultsJUnitTest.java
new file mode 100644
index 0000000..778e372
--- /dev/null
+++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/results/PageResultsJUnitTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.cache.lucene.internal.results;
+
+import static org.junit.Assert.*;
+
+import org.apache.geode.internal.DSFIDFactory;
+import org.apache.geode.internal.DataSerializableFixedID;
+import org.apache.geode.internal.util.BlobHelper;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.IOException;
+
+@Category(UnitTest.class)
+public class PageResultsJUnitTest {
+
+  @Test
+  public void serializationShouldNotChangeObject() throws IOException, ClassNotFoundException {
+    DSFIDFactory.registerDSFID(DataSerializableFixedID.LUCENE_PAGE_RESULTS, PageResults.class);
+    PageResults results = new PageResults();
+    results.add(new PageEntry("key1", "value1"));
+    results.add(new PageEntry("key2", "value2"));
+
+    byte[] serialized = BlobHelper.serializeToBlob(results);
+    PageResults newResults = (PageResults) BlobHelper.deserializeBlob(serialized);
+
+    assertEquals(newResults, results);
+  }
+
+}