This is an automated email from the ASF dual-hosted git repository.
jiangtian pushed a commit to branch cluster_new
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git
The following commit(s) were added to refs/heads/cluster_new by this push:
new 96cbb3a [IOTDB-781] Support AlterTimeSeriesPlan in distributed version
new 1030519 Merge pull request #1405 from neuyilan/cluster_new_IOTDB-781
96cbb3a is described below
commit 96cbb3ab6e83a19287181fa13660ead6cc4b0163
Author: HouliangQi <[email protected]>
AuthorDate: Mon Jun 22 15:37:56 2020 +0800
[IOTDB-781] Support AlterTimeSeriesPlan in distributed version
---
.../iotdb/cluster/query/ClusterPlanRouter.java | 16 ++-
.../apache/iotdb/cluster/utils/PartitionUtils.java | 6 +-
.../apache/iotdb/db/qp/physical/PhysicalPlan.java | 7 +-
.../db/qp/physical/sys/AlterTimeSeriesPlan.java | 136 ++++++++++++++++++--
.../iotdb/tsfile/utils/ReadWriteIOUtils.java | 100 +++++++--------
.../iotdb/tsfile/utils/ReadWriteIOUtilsTest.java | 142 +++++++++++++++++++++
6 files changed, 337 insertions(+), 70 deletions(-)
diff --git
a/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterPlanRouter.java
b/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterPlanRouter.java
index 8403d24..fb5d814 100644
---
a/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterPlanRouter.java
+++
b/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterPlanRouter.java
@@ -37,6 +37,7 @@ import org.apache.iotdb.db.qp.physical.PhysicalPlan;
import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
import org.apache.iotdb.db.qp.physical.crud.InsertTabletPlan;
import org.apache.iotdb.db.qp.physical.crud.UpdatePlan;
+import org.apache.iotdb.db.qp.physical.sys.AlterTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.CountPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.ShowChildPathsPlan;
@@ -115,6 +116,8 @@ public class ClusterPlanRouter {
return splitAndRoutePlan((CreateTimeSeriesPlan) plan);
} else if (plan instanceof InsertPlan) {
return splitAndRoutePlan((InsertPlan) plan);
+ } else if (plan instanceof AlterTimeSeriesPlan) {
+ return splitAndRoutePlan((AlterTimeSeriesPlan) plan);
}
//the if clause can be removed after the program is stable
if (PartitionUtils.isLocalNonQueryPlan(plan)) {
@@ -135,6 +138,13 @@ public class ClusterPlanRouter {
return Collections.singletonMap(plan, partitionGroup);
}
+ public Map<PhysicalPlan, PartitionGroup>
splitAndRoutePlan(AlterTimeSeriesPlan plan)
+ throws MetadataException {
+ PartitionGroup partitionGroup =
+ partitionTable.partitionByPathTime(plan.getPath().getFullPath(), 0);
+ return Collections.singletonMap(plan, partitionGroup);
+ }
+
public Map<PhysicalPlan, PartitionGroup>
splitAndRoutePlan(CreateTimeSeriesPlan plan)
throws MetadataException {
PartitionGroup partitionGroup =
@@ -151,7 +161,8 @@ public class ClusterPlanRouter {
if (times.length == 0) {
return Collections.emptyMap();
}
- long startTime = (times[0] / StorageEngine.getTimePartitionInterval()) *
StorageEngine.getTimePartitionInterval();//included
+ long startTime = (times[0] / StorageEngine.getTimePartitionInterval()) *
StorageEngine
+ .getTimePartitionInterval();//included
long endTime = startTime +
StorageEngine.getTimePartitionInterval();//excluded
int startLoc = 0; //included
@@ -168,7 +179,8 @@ public class ClusterPlanRouter {
startLoc = i;
startTime = endTime;
endTime =
- (times[i] / StorageEngine.getTimePartitionInterval() + 1) *
StorageEngine.getTimePartitionInterval();
+ (times[i] / StorageEngine.getTimePartitionInterval() + 1) *
StorageEngine
+ .getTimePartitionInterval();
}
}
//the final range
diff --git
a/cluster/src/main/java/org/apache/iotdb/cluster/utils/PartitionUtils.java
b/cluster/src/main/java/org/apache/iotdb/cluster/utils/PartitionUtils.java
index b0813e9..58c9fe6 100644
--- a/cluster/src/main/java/org/apache/iotdb/cluster/utils/PartitionUtils.java
+++ b/cluster/src/main/java/org/apache/iotdb/cluster/utils/PartitionUtils.java
@@ -103,8 +103,10 @@ public class PartitionUtils {
* @return is globalDataPlan or not
*/
public static boolean isGlobalDataPlan(PhysicalPlan plan) {
- return plan instanceof DeletePlan // because deletePlan has an infinite
time range.
- || plan instanceof DeleteTimeSeriesPlan;
+ return
+ // because deletePlan has an infinite time range.
+ plan instanceof DeletePlan
+ || plan instanceof DeleteTimeSeriesPlan;
}
public static int calculateStorageGroupSlotByTime(String storageGroupName,
long timestamp,
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
b/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
index 5d30f66..39daae5 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
@@ -28,6 +28,7 @@ import org.apache.iotdb.db.qp.logical.Operator.OperatorType;
import org.apache.iotdb.db.qp.physical.crud.InsertTabletPlan;
import org.apache.iotdb.db.qp.physical.crud.DeletePlan;
import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
+import org.apache.iotdb.db.qp.physical.sys.AlterTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.AuthorPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.DataAuthPlan;
@@ -257,6 +258,10 @@ public abstract class PhysicalPlan {
plan = new LoadConfigurationPlan();
plan.deserialize(buffer);
break;
+ case ALTER_TIMESERIES:
+ plan = new AlterTimeSeriesPlan();
+ plan.deserialize(buffer);
+ break;
default:
throw new IOException("unrecognized log type " + type);
}
@@ -267,7 +272,7 @@ public abstract class PhysicalPlan {
public enum PhysicalPlanType {
INSERT, DELETE, BATCHINSERT, SET_STORAGE_GROUP, CREATE_TIMESERIES, TTL,
GRANT_WATERMARK_EMBEDDING, REVOKE_WATERMARK_EMBEDDING,
CREATE_ROLE, DELETE_ROLE, CREATE_USER, REVOKE_USER_ROLE,
REVOKE_ROLE_PRIVILEGE, REVOKE_USER_PRIVILEGE, GRANT_ROLE_PRIVILEGE,
GRANT_USER_PRIVILEGE, GRANT_USER_ROLE, MODIFY_PASSWORD, DELETE_USER,
- DELETE_STORAGE_GROUP, SHOW_TIMESERIES, DELETE_TIMESERIES,
LOAD_CONFIGURATION
+ DELETE_STORAGE_GROUP, SHOW_TIMESERIES, DELETE_TIMESERIES,
LOAD_CONFIGURATION, ALTER_TIMESERIES
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/AlterTimeSeriesPlan.java
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/AlterTimeSeriesPlan.java
index e8020e3..814b7cb 100644
---
a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/AlterTimeSeriesPlan.java
+++
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/AlterTimeSeriesPlan.java
@@ -19,32 +19,48 @@
package org.apache.iotdb.db.qp.physical.sys;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.logical.Operator.OperatorType;
import org.apache.iotdb.db.qp.logical.sys.AlterTimeSeriesOperator;
import org.apache.iotdb.db.qp.logical.sys.AlterTimeSeriesOperator.AlterType;
import org.apache.iotdb.db.qp.physical.PhysicalPlan;
import org.apache.iotdb.tsfile.read.common.Path;
+import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
public class AlterTimeSeriesPlan extends PhysicalPlan {
- private final Path path;
+ private Path path;
- private final AlterTimeSeriesOperator.AlterType alterType;
+ private AlterType alterType;
- // used when the alterType is RENAME, SET, DROP, ADD_TAGS, ADD_ATTRIBUTES
- // when the alterType is RENAME, alterMap has only one entry, key is the
beforeName, value is the
- // currentName
- // when the alterType is DROP, only the keySet of alterMap is useful, it
contains all the key
- // names needed to be removed
- private final Map<String, String> alterMap;
+ /**
+ * used when the alterType is RENAME, SET, DROP, ADD_TAGS, ADD_ATTRIBUTES.
when the alterType is
+ * RENAME, alterMap has only one entry, key is the beforeName, value is the
currentName. when the
+ * alterType is DROP, only the keySet of alterMap is useful, it contains all
the key names needed
+ * to be removed
+ */
+ private Map<String, String> alterMap;
- // used when the alterType is UPSERT
- private final String alias;
- private final Map<String, String> tagsMap;
- private final Map<String, String> attributesMap;
+ /**
+ * used when the alterType is UPSERT
+ */
+ private String alias;
+ private Map<String, String> tagsMap;
+ private Map<String, String> attributesMap;
+
+ /**
+ * used only for deserialize
+ */
+ public AlterTimeSeriesPlan() {
+ super(false, OperatorType.ALTER_TIMESERIES);
+ }
public AlterTimeSeriesPlan(Path path, AlterType alterType, Map<String,
String> alterMap,
String alias, Map<String, String> tagsMap, Map<String, String>
attributesMap) {
@@ -85,4 +101,100 @@ public class AlterTimeSeriesPlan extends PhysicalPlan {
public List<Path> getPaths() {
return Collections.singletonList(path);
}
+
+ @Override
+ public void serialize(DataOutputStream stream) throws IOException {
+ stream.writeByte((byte) PhysicalPlanType.ALTER_TIMESERIES.ordinal());
+ byte[] bytes = path.getFullPath().getBytes();
+ stream.writeInt(bytes.length);
+ stream.write(bytes);
+
+ stream.write(alterType.ordinal());
+
+ // alias
+ if (alias != null) {
+ stream.write(1);
+ ReadWriteIOUtils.write(alias, stream);
+ } else {
+ stream.write(0);
+ }
+
+ // alterMap
+ if (alterMap != null && !alterMap.isEmpty()) {
+ stream.write(1);
+ ReadWriteIOUtils.write(alterMap, stream);
+ } else {
+ stream.write(0);
+ }
+
+ // tagsMap
+ if (tagsMap != null && !tagsMap.isEmpty()) {
+ stream.write(1);
+ ReadWriteIOUtils.write(tagsMap, stream);
+ } else {
+ stream.write(0);
+ }
+
+ // attributesMap
+ if (attributesMap != null && !attributesMap.isEmpty()) {
+ stream.write(1);
+ ReadWriteIOUtils.write(attributesMap, stream);
+ } else {
+ stream.write(0);
+ }
+ }
+
+ @Override
+ public void deserialize(ByteBuffer buffer) {
+ int length = buffer.getInt();
+ byte[] bytes = new byte[length];
+ buffer.get(bytes);
+ path = new Path(new String(bytes));
+
+ alterType = AlterType.values()[buffer.get()];
+
+ // alias
+ if (buffer.get() == 1) {
+ alias = ReadWriteIOUtils.readString(buffer);
+ }
+
+ // alterMap
+ if (buffer.get() == 1) {
+ alterMap = ReadWriteIOUtils.readMap(buffer);
+ }
+
+ // tagsMap
+ if (buffer.get() == 1) {
+ tagsMap = ReadWriteIOUtils.readMap(buffer);
+ }
+
+ // attributesMap
+ if (buffer.get() == 1) {
+ attributesMap = ReadWriteIOUtils.readMap(buffer);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ AlterTimeSeriesPlan that = (AlterTimeSeriesPlan) o;
+
+ return Objects.equals(path, that.path) &&
+ alterType != that.alterType &&
+ Objects.equals(alterMap, that.alterMap) &&
+ Objects.equals(alias, that.alias) &&
+ Objects.equals(tagsMap, that.tagsMap) &&
+ Objects.equals(attributesMap, that.attributesMap);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(path, alias, alterType, alterMap, attributesMap,
tagsMap);
+ }
}
diff --git
a/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/ReadWriteIOUtils.java
b/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/ReadWriteIOUtils.java
index 4d55f16..6810abc 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/ReadWriteIOUtils.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/ReadWriteIOUtils.java
@@ -93,7 +93,7 @@ public class ReadWriteIOUtils {
* read bytes array in given size
*
* @param buffer buffer
- * @param size size
+ * @param size size
* @return bytes array
*/
public static byte[] readBytes(ByteBuffer buffer, int size) {
@@ -136,22 +136,12 @@ public class ReadWriteIOUtils {
stream.writeInt(map.size());
length += 4;
for (Entry<String, String> entry : map.entrySet()) {
- bytes = entry.getKey().getBytes();
- stream.writeInt(bytes.length);
- length += 4;
- stream.write(bytes);
- length += bytes.length;
- bytes = entry.getValue().getBytes();
- stream.writeInt(bytes.length);
- length += 4;
- stream.write(bytes);
- length += bytes.length;
+ length += write(entry.getKey(), stream);
+ length += write(entry.getValue(), stream);
}
return length;
}
-
-
/**
* write a int value to outputStream according to flag. If flag is true,
write 1, else write 0.
*/
@@ -244,8 +234,6 @@ public class ReadWriteIOUtils {
return INT_LEN;
}
-
-
/**
* write the size (int) of the binary and then the bytes in binary
*/
@@ -331,6 +319,11 @@ public class ReadWriteIOUtils {
*/
public static int write(String s, OutputStream outputStream) throws
IOException {
int len = 0;
+ if (s == null) {
+ len += write(0, outputStream);
+ return len;
+ }
+
byte[] bytes = s.getBytes();
len += write(bytes.length, outputStream);
outputStream.write(bytes);
@@ -370,7 +363,8 @@ public class ReadWriteIOUtils {
/**
* write byteBuffer.array to outputStream without capacity.
*/
- public static int writeWithoutSize(ByteBuffer byteBuffer, OutputStream
outputStream) throws IOException {
+ public static int writeWithoutSize(ByteBuffer byteBuffer, OutputStream
outputStream)
+ throws IOException {
byte[] bytes = byteBuffer.array();
outputStream.write(bytes);
return bytes.length;
@@ -566,7 +560,7 @@ public class ReadWriteIOUtils {
*/
public static String readString(ByteBuffer buffer) {
int strLength = readInt(buffer);
- if (strLength < 0) {
+ if (strLength <= 0) {
return null;
}
byte[] bytes = new byte[strLength];
@@ -668,7 +662,7 @@ public class ReadWriteIOUtils {
/**
* read bytes from byteBuffer, this method makes sure that you can read
length bytes or reach to
* the end of the buffer.
- *
+ * <p>
* read a int + buffer
*/
public static ByteBuffer readByteBufferWithSelfDescriptionLength(ByteBuffer
buffer) {
@@ -823,8 +817,8 @@ public class ReadWriteIOUtils {
/**
- * to check whether the byte buffer is reach the magic string
- * this method doesn't change the position of the byte buffer
+ * to check whether the byte buffer is reach the magic string this method
doesn't change the
+ * position of the byte buffer
*
* @param byteBuffer byte buffer
* @return whether the byte buffer is reach the magic string
@@ -837,8 +831,8 @@ public class ReadWriteIOUtils {
}
/**
- * to check whether the inputStream is reach the magic string
- * this method doesn't change the position of the inputStream
+ * to check whether the inputStream is reach the magic string this method
doesn't change the
+ * position of the inputStream
*
* @param inputStream inputStream
* @return whether the inputStream is reach the magic string
@@ -852,38 +846,38 @@ public class ReadWriteIOUtils {
}
public static void writeObject(Object value, DataOutputStream outputStream) {
- try {
- if (value instanceof Long) {
- outputStream.write(LONG.ordinal());
- outputStream.writeLong((Long) value);
- } else if (value instanceof Double) {
- outputStream.write(DOUBLE.ordinal());
- outputStream.writeDouble((Double) value);
- } else if (value instanceof Integer) {
- outputStream.write(INTEGER.ordinal());
- outputStream.writeInt((Integer) value);
- } else if (value instanceof Float) {
- outputStream.write(FLOAT.ordinal());
- outputStream.writeFloat((Float) value);
- } else if (value instanceof Binary) {
- outputStream.write(BINARY.ordinal());
- byte[] bytes = ((Binary) value).getValues();
- outputStream.writeInt(bytes.length);
- outputStream.write(bytes);
- } else if (value instanceof Boolean) {
- outputStream.write(BOOLEAN.ordinal());
- outputStream.write(((Boolean) value) ? 1 : 0);
- } else if (value == null) {
- outputStream.write(NULL.ordinal());
- } else {
- outputStream.write(STRING.ordinal());
- byte[] bytes = value.toString().getBytes();
- outputStream.writeInt(bytes.length);
- outputStream.write(bytes);
- }
- } catch (IOException ignored) {
- // ignored
+ try {
+ if (value instanceof Long) {
+ outputStream.write(LONG.ordinal());
+ outputStream.writeLong((Long) value);
+ } else if (value instanceof Double) {
+ outputStream.write(DOUBLE.ordinal());
+ outputStream.writeDouble((Double) value);
+ } else if (value instanceof Integer) {
+ outputStream.write(INTEGER.ordinal());
+ outputStream.writeInt((Integer) value);
+ } else if (value instanceof Float) {
+ outputStream.write(FLOAT.ordinal());
+ outputStream.writeFloat((Float) value);
+ } else if (value instanceof Binary) {
+ outputStream.write(BINARY.ordinal());
+ byte[] bytes = ((Binary) value).getValues();
+ outputStream.writeInt(bytes.length);
+ outputStream.write(bytes);
+ } else if (value instanceof Boolean) {
+ outputStream.write(BOOLEAN.ordinal());
+ outputStream.write(((Boolean) value) ? 1 : 0);
+ } else if (value == null) {
+ outputStream.write(NULL.ordinal());
+ } else {
+ outputStream.write(STRING.ordinal());
+ byte[] bytes = value.toString().getBytes();
+ outputStream.writeInt(bytes.length);
+ outputStream.write(bytes);
}
+ } catch (IOException ignored) {
+ // ignored
+ }
}
public static Object readObject(ByteBuffer buffer) {
diff --git
a/tsfile/src/test/java/org/apache/iotdb/tsfile/utils/ReadWriteIOUtilsTest.java
b/tsfile/src/test/java/org/apache/iotdb/tsfile/utils/ReadWriteIOUtilsTest.java
new file mode 100644
index 0000000..20cde42
--- /dev/null
+++
b/tsfile/src/test/java/org/apache/iotdb/tsfile/utils/ReadWriteIOUtilsTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.iotdb.tsfile.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ReadWriteIOUtilsTest {
+
+ protected static final int DEFAULT_BUFFER_SIZE = 4096;
+
+ @Test
+ public void readStringBufferTest() {
+ // 1. not null value
+ String str = "string";
+ ByteArrayOutputStream byteArrayOutputStream = new
ByteArrayOutputStream(DEFAULT_BUFFER_SIZE);
+ DataOutputStream stream = new DataOutputStream(byteArrayOutputStream);
+ try {
+ ReadWriteIOUtils.write(str, stream);
+ } catch (IOException e) {
+ Assert.assertEquals("why failed?", e.toString());
+ }
+
+ String result = null;
+ result =
ReadWriteIOUtils.readString(ByteBuffer.wrap(byteArrayOutputStream.toByteArray()));
+ Assert.assertNotNull(result);
+ Assert.assertEquals(str, result);
+
+ //2. null value
+ str = null;
+ byteArrayOutputStream = new ByteArrayOutputStream(DEFAULT_BUFFER_SIZE);
+ stream = new DataOutputStream(byteArrayOutputStream);
+ try {
+ ReadWriteIOUtils.write(str, stream);
+ } catch (IOException e) {
+ Assert.assertEquals("why failed?", e.toString());
+ }
+
+ result = null;
+ result =
ReadWriteIOUtils.readString(ByteBuffer.wrap(byteArrayOutputStream.toByteArray()));
+ Assert.assertNull(result);
+ Assert.assertEquals(str, result);
+ }
+
+ @Test
+ public void readMapTest() {
+ // 1. key: not null; value: not null
+ String key = "string";
+ String value = "string";
+ Map map = new HashMap<String, String>();
+ map.put(key, value);
+ ByteArrayOutputStream byteArrayOutputStream = new
ByteArrayOutputStream(DEFAULT_BUFFER_SIZE);
+ DataOutputStream stream = new DataOutputStream(byteArrayOutputStream);
+ try {
+ ReadWriteIOUtils.write(map, stream);
+ } catch (IOException e) {
+ Assert.assertEquals("why failed?", e.toString());
+ }
+
+ Map result = null;
+ result =
ReadWriteIOUtils.readMap(ByteBuffer.wrap(byteArrayOutputStream.toByteArray()));
+ Assert.assertNotNull(result);
+ Assert.assertEquals(map, result);
+
+ // 2. key: not null; value: null
+ key = "string";
+ value = null;
+ map.clear();
+ map.put(key, value);
+ byteArrayOutputStream = new ByteArrayOutputStream(DEFAULT_BUFFER_SIZE);
+ stream = new DataOutputStream(byteArrayOutputStream);
+ try {
+ ReadWriteIOUtils.write(map, stream);
+ } catch (IOException e) {
+ Assert.assertEquals("why failed?", e.toString());
+ }
+
+ result = null;
+ result =
ReadWriteIOUtils.readMap(ByteBuffer.wrap(byteArrayOutputStream.toByteArray()));
+ Assert.assertNotNull(result);
+ Assert.assertEquals(map, result);
+
+ // 3. key: null; value: not null
+ key = null;
+ value = "string";
+ map.clear();
+ map.put(key, value);
+ byteArrayOutputStream = new ByteArrayOutputStream(DEFAULT_BUFFER_SIZE);
+ stream = new DataOutputStream(byteArrayOutputStream);
+ try {
+ ReadWriteIOUtils.write(map, stream);
+ } catch (IOException e) {
+ Assert.assertEquals("why failed?", e.toString());
+ }
+
+ result = null;
+ result =
ReadWriteIOUtils.readMap(ByteBuffer.wrap(byteArrayOutputStream.toByteArray()));
+ Assert.assertNotNull(result);
+ Assert.assertEquals(map, result);
+
+ // 4. key: null; value: null
+ key = null;
+ value = null;
+ map.clear();
+ map.put(key, value);
+ byteArrayOutputStream = new ByteArrayOutputStream(DEFAULT_BUFFER_SIZE);
+ stream = new DataOutputStream(byteArrayOutputStream);
+ try {
+ ReadWriteIOUtils.write(map, stream);
+ } catch (IOException e) {
+ Assert.assertEquals("why failed?", e.toString());
+ }
+
+ result = null;
+ result =
ReadWriteIOUtils.readMap(ByteBuffer.wrap(byteArrayOutputStream.toByteArray()));
+ Assert.assertNotNull(result);
+ Assert.assertEquals(map, result);
+
+ }
+}