This is an automated email from the ASF dual-hosted git repository.

rpuch pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 267ac43992 IGNITE-23473 Do not use ByteUtils#toBytes to persist 
IndexMeta (#4583)
267ac43992 is described below

commit 267ac439925df886d1a885fc346355aca467ce35
Author: Roman Puchkovskiy <[email protected]>
AuthorDate: Fri Oct 18 16:51:38 2024 +0400

    IGNITE-23473 Do not use ByteUtils#toBytes to persist IndexMeta (#4583)
---
 .../table/distributed/index/IndexMeta.java         | 11 +--
 .../distributed/index/IndexMetaSerializer.java     | 91 ++++++++++++++++++++++
 .../table/distributed/index/IndexMetaStorage.java  |  7 +-
 .../table/distributed/index/MetaIndexStatus.java   | 61 +++++++++++++--
 .../distributed/index/MetaIndexStatusChange.java   |  5 +-
 .../index/BaseIndexMetaStorageTest.java            |  3 +-
 .../distributed/index/IndexMetaSerializerTest.java | 79 +++++++++++++++++++
 .../distributed/index/MetaIndexStatusTest.java     | 35 +++++++++
 8 files changed, 270 insertions(+), 22 deletions(-)

diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/IndexMeta.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/IndexMeta.java
index d973b35e8d..ffd3f0cf0e 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/IndexMeta.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/IndexMeta.java
@@ -19,7 +19,6 @@ package org.apache.ignite.internal.table.distributed.index;
 
 import static java.util.Collections.unmodifiableMap;
 
-import java.io.Serializable;
 import java.util.EnumMap;
 import java.util.Map;
 import org.apache.ignite.internal.catalog.Catalog;
@@ -30,21 +29,19 @@ import org.apache.ignite.internal.tostring.S;
 import org.jetbrains.annotations.Nullable;
 
 /** Immutable index meta, based on the {@link CatalogIndexDescriptor}. */
-public class IndexMeta implements Serializable {
-    private static final long serialVersionUID = 1044129530453957897L;
-
+public class IndexMeta {
     private final int catalogVersion;
 
     private final int indexId;
 
     private final int tableId;
 
+    private final int tableVersionOnIndexCreation;
+
     private final String indexName;
 
     private final MetaIndexStatus currentStatus;
 
-    private final int tableVersionOnIndexCreation;
-
     @IgniteToStringInclude
     private final Map<MetaIndexStatus, MetaIndexStatusChange> statusChanges;
 
@@ -59,7 +56,7 @@ public class IndexMeta implements Serializable {
      * @param currentStatus Current status of the index
      * @param statusChanges <b>Immutable</b> map of index statuses with change 
info (for example catalog version) in which they appeared.
      */
-    private IndexMeta(
+    IndexMeta(
             int catalogVersion,
             int indexId,
             int tableId,
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/IndexMetaSerializer.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/IndexMetaSerializer.java
new file mode 100644
index 0000000000..0462bcfb94
--- /dev/null
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/IndexMetaSerializer.java
@@ -0,0 +1,91 @@
+/*
+ * 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.ignite.internal.table.distributed.index;
+
+import java.io.IOException;
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.apache.ignite.internal.util.io.IgniteDataInput;
+import org.apache.ignite.internal.util.io.IgniteDataOutput;
+import org.apache.ignite.internal.versioned.VersionedSerializer;
+
+/**
+ * {@link VersionedSerializer} for {@link IndexMeta} instances.
+ */
+class IndexMetaSerializer extends VersionedSerializer<IndexMeta> {
+    static final IndexMetaSerializer INSTANCE = new IndexMetaSerializer();
+
+    @Override
+    protected void writeExternalData(IndexMeta meta, IgniteDataOutput out) 
throws IOException {
+        out.writeVarInt(meta.catalogVersion());
+        out.writeVarInt(meta.indexId());
+        out.writeVarInt(meta.tableId());
+        out.writeVarInt(meta.tableVersion());
+        out.writeUTF(meta.indexName());
+        out.writeVarInt(meta.status().code());
+
+        out.writeVarInt(meta.statusChanges().size());
+        for (Entry<MetaIndexStatus, MetaIndexStatusChange> entry : 
meta.statusChanges().entrySet()) {
+            out.writeVarInt(entry.getKey().code());
+
+            MetaIndexStatusChange change = entry.getValue();
+            out.writeVarInt(change.catalogVersion());
+            // Writing long and not varlong as the latter requires 9 bytes.
+            out.writeLong(change.activationTimestamp());
+        }
+    }
+
+    @Override
+    protected IndexMeta readExternalData(byte protoVer, IgniteDataInput in) 
throws IOException {
+        int catalogVersion = in.readVarIntAsInt();
+        int indexId = in.readVarIntAsInt();
+        int tableId = in.readVarIntAsInt();
+        int tableVersion = in.readVarIntAsInt();
+        String indexName = in.readUTF();
+        MetaIndexStatus status = 
MetaIndexStatus.findByCode(in.readVarIntAsInt());
+        Map<MetaIndexStatus, MetaIndexStatusChange> statusChanges = 
readStatusChanges(in);
+
+        return new IndexMeta(
+                catalogVersion,
+                indexId,
+                tableId,
+                tableVersion,
+                indexName,
+                status,
+                statusChanges
+        );
+    }
+
+    private static Map<MetaIndexStatus, MetaIndexStatusChange> 
readStatusChanges(IgniteDataInput in) throws IOException {
+        int length = in.readVarIntAsInt();
+
+        Map<MetaIndexStatus, MetaIndexStatusChange> map = new 
EnumMap<>(MetaIndexStatus.class);
+        for (int i = 0; i < length; i++) {
+            MetaIndexStatus status = 
MetaIndexStatus.findByCode(in.readVarIntAsInt());
+
+            int catalogVersion = in.readVarIntAsInt();
+            long activationTimestamp = in.readLong();
+            MetaIndexStatusChange change = new 
MetaIndexStatusChange(catalogVersion, activationTimestamp);
+
+            map.put(status, change);
+        }
+
+        return map;
+    }
+}
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/IndexMetaStorage.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/IndexMetaStorage.java
index 34feaed67e..afaf721fef 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/IndexMetaStorage.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/IndexMetaStorage.java
@@ -40,7 +40,6 @@ import static 
org.apache.ignite.internal.table.distributed.index.MetaIndexStatus
 import static 
org.apache.ignite.internal.table.distributed.index.MetaIndexStatus.REMOVED;
 import static 
org.apache.ignite.internal.table.distributed.index.MetaIndexStatus.statusOnRemoveIndex;
 import static org.apache.ignite.internal.util.ByteUtils.intToBytesKeepingOrder;
-import static org.apache.ignite.internal.util.ByteUtils.toBytes;
 import static org.apache.ignite.internal.util.CollectionUtils.difference;
 import static 
org.apache.ignite.internal.util.CompletableFutures.falseCompletedFuture;
 import static 
org.apache.ignite.internal.util.CompletableFutures.nullCompletedFuture;
@@ -80,8 +79,8 @@ import org.apache.ignite.internal.manager.ComponentContext;
 import org.apache.ignite.internal.manager.IgniteComponent;
 import org.apache.ignite.internal.metastorage.Entry;
 import org.apache.ignite.internal.metastorage.MetaStorageManager;
-import org.apache.ignite.internal.util.ByteUtils;
 import org.apache.ignite.internal.util.Cursor;
+import org.apache.ignite.internal.versioned.VersionedSerialization;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -409,7 +408,7 @@ public class IndexMetaStorage implements IgniteComponent {
             return cursor.stream()
                     .map(Entry::value)
                     .filter(Objects::nonNull)
-                    .map(entryBytes -> (IndexMeta) 
ByteUtils.fromBytes(entryBytes))
+                    .map(entryBytes -> 
VersionedSerialization.fromBytes(entryBytes, IndexMetaSerializer.INSTANCE))
                     .collect(toMap(IndexMeta::indexId, Function.identity()));
         }
     }
@@ -446,7 +445,7 @@ public class IndexMetaStorage implements IgniteComponent {
                 value(versionKey).lt(versionValue),
                 List.of(
                         put(versionKey, versionValue),
-                        put(indexMetaValueKey(newMeta), toBytes(newMeta))
+                        put(indexMetaValueKey(newMeta), 
VersionedSerialization.toBytes(newMeta, IndexMetaSerializer.INSTANCE))
                 ),
                 List.of(noop())
         );
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/MetaIndexStatus.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/MetaIndexStatus.java
index c58ed21c96..9b3c162bd5 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/MetaIndexStatus.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/MetaIndexStatus.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.table.distributed.index;
 
+import java.util.HashSet;
+import java.util.Set;
 import org.apache.ignite.internal.catalog.descriptors.CatalogIndexStatus;
 
 /** Index status as stored in the {@link IndexMeta}. */
@@ -26,35 +28,35 @@ public enum MetaIndexStatus {
      *
      * @see CatalogIndexStatus#REGISTERED
      */
-    REGISTERED,
+    REGISTERED(0),
 
     /**
      * Index was in the process of being built.
      *
      * @see CatalogIndexStatus#BUILDING
      */
-    BUILDING,
+    BUILDING(1),
 
     /**
      * Index has been successfully built and is available for reading from it.
      *
      * @see CatalogIndexStatus#AVAILABLE
      */
-    AVAILABLE,
+    AVAILABLE(2),
 
     /**
      * Available index has started preparing to be removed from the catalog.
      *
      * @see CatalogIndexStatus#STOPPING
      */
-    STOPPING,
+    STOPPING(3),
 
     /**
      * Index has been removed from the catalog, with {@link 
CatalogIndexStatus#REGISTERED}/{@link CatalogIndexStatus#BUILDING} statuses, but
      * has not yet been destroyed due to a low watermark.
      */
     // TODO: IGNITE-20934 Get rid of such indexes immediately
-    REMOVED,
+    REMOVED(4),
 
     /**
      * Index has been removed from the catalog, with statuses {@link 
CatalogIndexStatus#AVAILABLE} (on table destruction) or
@@ -62,7 +64,54 @@ public enum MetaIndexStatus {
      *
      * <p>Such an index cannot be used by RW transactions, only by RO 
transactions with the correct readTimestamp.</p>
      */
-    READ_ONLY;
+    READ_ONLY(5);
+
+    /** Status code. It's persisted and should not be changed for existing 
statuses. */
+    private final int code;
+
+    private static final MetaIndexStatus[] VALUES_INDEXED_BY_CODE;
+
+    static {
+        int maxCode = -1;
+        Set<Integer> seenCodes = new HashSet<>();
+        for (MetaIndexStatus status : values()) {
+            assert status.code >= 0 : status + " has a negative code";
+            maxCode = Math.max(maxCode, status.code);
+
+            boolean added = seenCodes.add(status.code);
+            assert added : "Duplicate status code for: " + status;
+        }
+
+        VALUES_INDEXED_BY_CODE = new MetaIndexStatus[maxCode + 1];
+        for (MetaIndexStatus status : values()) {
+            VALUES_INDEXED_BY_CODE[status.code] = status;
+        }
+    }
+
+    MetaIndexStatus(int code) {
+        this.code = code;
+    }
+
+    /**
+     * Finds status by code.
+     *
+     * @param code Code to use when searching.
+     * @throws IllegalArgumentException If there is no status with the 
provided code.
+     */
+    static MetaIndexStatus findByCode(int code) {
+        MetaIndexStatus status = VALUES_INDEXED_BY_CODE[code];
+
+        if (status == null) {
+            throw new IllegalArgumentException("Unknown code [" + code + "]");
+        }
+
+        return status;
+    }
+
+    /** Returns status code (the code is persisted and should not be changed 
for existing statuses). */
+    public int code() {
+        return code;
+    }
 
     /** Converts {@link CatalogIndexStatus} to {@link MetaIndexStatus}. */
     public static MetaIndexStatus convert(CatalogIndexStatus 
catalogIndexStatus) {
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/MetaIndexStatusChange.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/MetaIndexStatusChange.java
index fdfdf1a069..72040807de 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/MetaIndexStatusChange.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/index/MetaIndexStatusChange.java
@@ -17,14 +17,11 @@
 
 package org.apache.ignite.internal.table.distributed.index;
 
-import java.io.Serializable;
 import org.apache.ignite.internal.catalog.Catalog;
 import org.apache.ignite.internal.tostring.S;
 
 /** Information about {@link MetaIndexStatus index status} changes. */
-public class MetaIndexStatusChange implements Serializable {
-    private static final long serialVersionUID = -2837971110813775936L;
-
+public class MetaIndexStatusChange {
     private final int catalogVersion;
 
     private final long activationTs;
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/index/BaseIndexMetaStorageTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/index/BaseIndexMetaStorageTest.java
index ea97cbba65..d3f49fd88f 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/index/BaseIndexMetaStorageTest.java
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/index/BaseIndexMetaStorageTest.java
@@ -52,6 +52,7 @@ import 
org.apache.ignite.internal.metastorage.MetaStorageManager;
 import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
 import org.apache.ignite.internal.util.ByteUtils;
 import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.versioned.VersionedSerialization;
 import org.jetbrains.annotations.Nullable;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -139,7 +140,7 @@ abstract class BaseIndexMetaStorageTest extends 
BaseIgniteAbstractTest {
         assertNotNull(versionBytes, "indexId=" + indexId);
 
         int catalogVersion = ByteUtils.bytesToIntKeepingOrder(versionBytes);
-        IndexMeta indexMeta = ByteUtils.fromBytes(valueBytes);
+        IndexMeta indexMeta = VersionedSerialization.fromBytes(valueBytes, 
IndexMetaSerializer.INSTANCE);
 
         assertEquals(indexMeta.catalogVersion(), catalogVersion, "indexId=" + 
indexId);
 
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/index/IndexMetaSerializerTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/index/IndexMetaSerializerTest.java
new file mode 100644
index 0000000000..c15c2be7ae
--- /dev/null
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/index/IndexMetaSerializerTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.ignite.internal.table.distributed.index;
+
+import static 
org.apache.ignite.internal.table.distributed.index.MetaIndexStatus.AVAILABLE;
+import static 
org.apache.ignite.internal.table.distributed.index.MetaIndexStatus.BUILDING;
+import static 
org.apache.ignite.internal.table.distributed.index.MetaIndexStatus.READ_ONLY;
+import static 
org.apache.ignite.internal.table.distributed.index.MetaIndexStatus.REGISTERED;
+import static 
org.apache.ignite.internal.table.distributed.index.MetaIndexStatus.REMOVED;
+import static 
org.apache.ignite.internal.table.distributed.index.MetaIndexStatus.STOPPING;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+
+import java.util.Base64;
+import java.util.Map;
+import org.apache.ignite.internal.versioned.VersionedSerialization;
+import org.junit.jupiter.api.Test;
+
+class IndexMetaSerializerTest {
+    private final IndexMetaSerializer serializer = new IndexMetaSerializer();
+
+    @Test
+    void serializationAndDeserialization() {
+        IndexMeta originalMeta = new IndexMeta(1000, 2000, 3000, 4000, 
"index", READ_ONLY, originalStatusChanges());
+
+        byte[] bytes = VersionedSerialization.toBytes(originalMeta, 
serializer);
+        IndexMeta restoredMeta = VersionedSerialization.fromBytes(bytes, 
serializer);
+
+        assertThat(restoredMeta.catalogVersion(), is(1000));
+        assertThat(restoredMeta.indexId(), is(2000));
+        assertThat(restoredMeta.tableId(), is(3000));
+        assertThat(restoredMeta.tableVersion(), is(4000));
+        assertThat(restoredMeta.indexName(), is("index"));
+        assertThat(restoredMeta.status(), is(READ_ONLY));
+        assertThat(restoredMeta.statusChanges(), 
equalTo(originalStatusChanges()));
+    }
+
+    private static Map<MetaIndexStatus, MetaIndexStatusChange> 
originalStatusChanges() {
+        return Map.of(
+                REGISTERED, new MetaIndexStatusChange(1, 100),
+                BUILDING, new MetaIndexStatusChange(2, 200),
+                AVAILABLE, new MetaIndexStatusChange(3, 300),
+                STOPPING, new MetaIndexStatusChange(4, 400),
+                REMOVED, new MetaIndexStatusChange(5, 500),
+                READ_ONLY, new MetaIndexStatusChange(6, 600)
+        );
+    }
+
+    @Test
+    void v1CanBeDeserialized() {
+        byte[] bytes = 
Base64.getDecoder().decode("Ae++Q+kH0Q+5F6EfBmluZGV4BgcCA8gAAAAAAAAAAwQsAQAAAAAAAAECZAAAAAAAAAAFBvQBAAAAAAAABAWQ"
+                + "AQAAAAAAAAYHWAIAAAAAAAA=");
+        IndexMeta restoredMeta = VersionedSerialization.fromBytes(bytes, 
serializer);
+
+        assertThat(restoredMeta.catalogVersion(), is(1000));
+        assertThat(restoredMeta.indexId(), is(2000));
+        assertThat(restoredMeta.tableId(), is(3000));
+        assertThat(restoredMeta.tableVersion(), is(4000));
+        assertThat(restoredMeta.indexName(), is("index"));
+        assertThat(restoredMeta.status(), is(READ_ONLY));
+        assertThat(restoredMeta.statusChanges(), 
equalTo(originalStatusChanges()));
+    }
+}
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/index/MetaIndexStatusTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/index/MetaIndexStatusTest.java
new file mode 100644
index 0000000000..733cd167b0
--- /dev/null
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/index/MetaIndexStatusTest.java
@@ -0,0 +1,35 @@
+/*
+ * 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.ignite.internal.table.distributed.index;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import org.junit.jupiter.api.Test;
+
+class MetaIndexStatusTest {
+    @Test
+    void codesAreStable() {
+        assertThat(MetaIndexStatus.REGISTERED.code(), is(0));
+        assertThat(MetaIndexStatus.BUILDING.code(), is(1));
+        assertThat(MetaIndexStatus.AVAILABLE.code(), is(2));
+        assertThat(MetaIndexStatus.STOPPING.code(), is(3));
+        assertThat(MetaIndexStatus.REMOVED.code(), is(4));
+        assertThat(MetaIndexStatus.READ_ONLY.code(), is(5));
+    }
+}

Reply via email to