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

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

commit e27bea7cec0426b62bf3f892b3088f2bc11d0aa0
Author: amashenkov <[email protected]>
AuthorDate: Thu Mar 16 00:04:04 2023 +0300

    WIP. Add descriptor classes for catalog's objects and CatalogService stub.
---
 modules/catalog/README.md                          |   7 ++
 modules/catalog/build.gradle                       |  36 +++++++
 .../ignite/internal/catalog/CatalogService.java    |  52 +++++++++++
 .../internal/catalog/CatalogServiceImpl.java       | 103 +++++++++++++++++++++
 .../catalog/descriptors/CatalogDescriptor.java     | 100 ++++++++++++++++++++
 .../catalog/descriptors/ColumnCollation.java       |  73 +++++++++++++++
 .../catalog/descriptors/HashIndexDescriptor.java   |  64 +++++++++++++
 .../catalog/descriptors/IndexColumnDescriptor.java |  52 +++++++++++
 .../catalog/descriptors/IndexDescriptor.java       |  60 ++++++++++++
 .../catalog/descriptors/ObjectDescriptor.java      |  62 +++++++++++++
 .../catalog/descriptors/SchemaDescriptor.java      |  90 ++++++++++++++++++
 .../catalog/descriptors/SortedIndexDescriptor.java |  59 ++++++++++++
 .../catalog/descriptors/TableColumnDescriptor.java |  75 +++++++++++++++
 .../catalog/descriptors/TableDescriptor.java       |  86 +++++++++++++++++
 .../internal/catalog/events/CatalogEvent.java      |  26 ++++++
 .../catalog/events/CatalogEventParameters.java     |  34 +++++++
 settings.gradle                                    |   2 +
 17 files changed, 981 insertions(+)

diff --git a/modules/catalog/README.md b/modules/catalog/README.md
new file mode 100644
index 0000000000..e21ccad796
--- /dev/null
+++ b/modules/catalog/README.md
@@ -0,0 +1,7 @@
+# Catalog module
+
+This module provides database catalog service implementation and descriptor 
for catalog objects.
+
+See 
[CatalogService](src/main/java/org/apache/ignite/internal/catalog/CatalogServiceImpl.java)
+
+TODO: IGNITE-18535 Add comprehensive description.
\ No newline at end of file
diff --git a/modules/catalog/build.gradle b/modules/catalog/build.gradle
new file mode 100644
index 0000000000..a126476f48
--- /dev/null
+++ b/modules/catalog/build.gradle
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+apply from: "$rootDir/buildscripts/java-core.gradle"
+apply from: "$rootDir/buildscripts/publishing.gradle"
+apply from: "$rootDir/buildscripts/java-junit5.gradle"
+
+dependencies {
+    annotationProcessor project(':ignite-configuration-annotation-processor')
+    annotationProcessor libs.auto.service
+    implementation libs.jetbrains.annotations
+
+    implementation project(':ignite-api')
+    implementation project(':ignite-core')
+    implementation project(':ignite-configuration')
+    implementation libs.jetbrains.annotations
+
+    testImplementation(testFixtures(project(':ignite-configuration')))
+    testImplementation(testFixtures(project(':ignite-core')))
+}
+
+description = "ignite-catalog"
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogService.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogService.java
new file mode 100644
index 0000000000..0767cbde36
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogService.java
@@ -0,0 +1,52 @@
+/*
+ * 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.catalog;
+
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+import org.apache.ignite.internal.catalog.descriptors.IndexDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.SchemaDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.TableDescriptor;
+import org.apache.ignite.internal.configuration.DynamicConfigurationChanger;
+
+/**
+ * Catalog service provides methods to access schema object's descriptors of 
exact version and/or last actual version at given timestamp,
+ * which is logical point-in-time.
+ *
+ * <p>Catalog service is responsible for proper configuration updates and 
storing/restoring schema evolution history (schema versions)
+ * for time-travelled queries purposes and lazy data evolution purposes.
+ *
+ * <p>TBD: schema manipulation methods.
+ * TBD: events
+ */
+public interface CatalogService {
+    TableDescriptor table(String tableName, long timestamp);
+
+    TableDescriptor table(int tableId, long timestamp);
+
+    IndexDescriptor index(int indexId, long timestamp);
+
+    Collection<IndexDescriptor> tableIndexes(int tableId, long timestamp);
+
+    SchemaDescriptor schema(int version);
+
+    SchemaDescriptor activeSchema(long timestamp);
+
+    //TODO: IGNITE-18535 enrich with schema manipulation methods.
+    CompletableFuture<SchemaDescriptor> 
updateSchema(DynamicConfigurationChanger changer);
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogServiceImpl.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogServiceImpl.java
new file mode 100644
index 0000000000..e46d1bc788
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogServiceImpl.java
@@ -0,0 +1,103 @@
+/*
+ * 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.catalog;
+
+import java.util.Collection;
+import java.util.Map.Entry;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentNavigableMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+import org.apache.ignite.internal.catalog.descriptors.CatalogDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.IndexDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.SchemaDescriptor;
+import org.apache.ignite.internal.catalog.descriptors.TableDescriptor;
+import org.apache.ignite.internal.catalog.events.CatalogEvent;
+import org.apache.ignite.internal.catalog.events.CatalogEventParameters;
+import org.apache.ignite.internal.configuration.DynamicConfigurationChanger;
+import org.apache.ignite.internal.manager.Producer;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * TODO: IGNITE-18535 Fix javadoc
+ */
+public class CatalogServiceImpl extends Producer<CatalogEvent, 
CatalogEventParameters> implements CatalogService {
+
+    /** Versioned catalog descriptors. */
+    private final ConcurrentMap<Integer, CatalogDescriptor> catalogByVer = new 
ConcurrentHashMap<>(); //TODO: IGNITE-18535 Use IntMap instead.
+
+    /** Versioned catalog descriptors sorted in chronological order. */
+    private final ConcurrentNavigableMap<Long, CatalogDescriptor> catalogByTs 
= new ConcurrentSkipListMap<>(); //TODO: IGNITE-18535 Use LongMap instead.
+
+    /** {@inheritDoc} */
+    @Override
+    public TableDescriptor table(String tableName, long timestamp) {
+        return 
catalogAt(timestamp).schema(CatalogDescriptor.DEFAULT_SCHEMA_NAME).table(tableName);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TableDescriptor table(int tableId, long timestamp) {
+        return catalogAt(timestamp).table(tableId);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexDescriptor index(int indexId, long timestamp) {
+        return catalogAt(timestamp).index(indexId);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<IndexDescriptor> tableIndexes(int tableId, long 
timestamp) {
+        return catalogAt(timestamp).tableIndexes(tableId);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public SchemaDescriptor schema(int version) {
+        return catalog(version).schema(CatalogDescriptor.DEFAULT_SCHEMA_NAME);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public @Nullable SchemaDescriptor activeSchema(long timestamp) {
+        return 
catalogAt(timestamp).schema(CatalogDescriptor.DEFAULT_SCHEMA_NAME);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public CompletableFuture<SchemaDescriptor> 
updateSchema(DynamicConfigurationChanger changer) {
+        return null;
+    }
+
+    private CatalogDescriptor catalog(int version) {
+        return catalogByVer.get(version);
+    }
+
+    private CatalogDescriptor catalogAt(long timestamp) {
+        Entry<Long, CatalogDescriptor> entry = 
catalogByTs.floorEntry(timestamp);
+
+        if (entry == null) {
+            throw new IllegalStateException("No valid schema found for given 
timestamp: " + timestamp);
+        }
+
+        return entry.getValue();
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/CatalogDescriptor.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/CatalogDescriptor.java
new file mode 100644
index 0000000000..9f5ba39ae3
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/CatalogDescriptor.java
@@ -0,0 +1,100 @@
+/*
+ * 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.catalog.descriptors;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.tostring.IgniteToStringExclude;
+import org.apache.ignite.internal.tostring.S;
+
+/**
+ * Catalog descriptor represents database schema snapshot.
+ */
+public class CatalogDescriptor implements Serializable {
+    public static final String DEFAULT_SCHEMA_NAME = "PUBLIC";
+    private static final long serialVersionUID = -2713639412596667759L;
+    private final int version;
+    private final long activationTimestamp;
+    private final Map<String, SchemaDescriptor> schemas;
+
+    @IgniteToStringExclude
+    private transient Map<Integer, TableDescriptor> tablesMap;
+    @IgniteToStringExclude
+    private transient Map<Integer, IndexDescriptor> indexesMap;
+
+
+    public CatalogDescriptor(int version, long activationTimestamp, 
SchemaDescriptor[] descriptors) {
+        this.version = version;
+        this.activationTimestamp = activationTimestamp;
+
+        Objects.requireNonNull(descriptors, "schemas");
+
+        assert descriptors.length > 0 : "No schemas found";
+        assert Arrays.stream(descriptors).allMatch(t -> t.version() == 
version) : "Invalid schema version";
+
+        schemas = 
Arrays.stream(descriptors).collect(Collectors.toUnmodifiableMap(SchemaDescriptor::name,
 t -> t));
+
+        rebuildMaps();
+    }
+
+    public long time() {
+        return activationTimestamp;
+    }
+
+    public SchemaDescriptor schema(String name) {
+        return schemas.get(name);
+    }
+
+    public TableDescriptor table(int tableId) {
+        return tablesMap.get(tableId);
+    }
+
+    public IndexDescriptor index(int indexId) {
+        return indexesMap.get(indexId);
+    }
+
+    public Collection<IndexDescriptor> tableIndexes(int tableId) {
+        return indexesMap.values().stream().filter(desc -> desc.tableId() == 
tableId).collect(Collectors.toList());
+    }
+
+    private void rebuildMaps() {
+        tablesMap = schemas.values().stream().flatMap(s -> 
Arrays.stream(s.tables()))
+                .collect(Collectors.toUnmodifiableMap(ObjectDescriptor::id, 
Function.identity()));
+        indexesMap = schemas.values().stream().flatMap(s -> 
Arrays.stream(s.indexes())).
+                collect(Collectors.toUnmodifiableMap(ObjectDescriptor::id, 
Function.identity()));
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, 
ClassNotFoundException {
+        in.defaultReadObject();
+
+        rebuildMaps();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return S.toString(this);
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/ColumnCollation.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/ColumnCollation.java
new file mode 100644
index 0000000000..1acb243625
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/ColumnCollation.java
@@ -0,0 +1,73 @@
+/*
+ * 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.catalog.descriptors;
+
+/**
+ * Enumeration of all supported collations.
+ */
+//TODO: IGNITE-18535 drop similar classes in index and sql-engine modules.
+public enum ColumnCollation {
+    ASC_NULLS_FIRST(true, true),
+    ASC_NULLS_LAST(true, false),
+    DESC_NULLS_FIRST(false, true),
+    DESC_NULLS_LAST(false, false);
+
+
+    private final boolean asc;
+    private final boolean nullsFirst;
+
+    /**
+     * Constructs the collation object.
+     *
+     * @param asc Direction of the sorting.
+     * @param nullsFirst Place of the null values in sorted range.
+     */
+    ColumnCollation(boolean asc, boolean nullsFirst) {
+        this.asc = asc;
+        this.nullsFirst = nullsFirst;
+    }
+
+    /**
+     * Returns collation object for given directions.
+     *
+     * @param asc Whether the values should be sorted in ascending order.
+     * @param nullsFirst Whether to put null values first.
+     * @return A collation object.
+     */
+    public static ColumnCollation get(boolean asc, boolean nullsFirst) {
+        if (asc && nullsFirst) {
+            return ASC_NULLS_FIRST;
+        } else if (asc) {
+            return ASC_NULLS_LAST;
+        } else if (nullsFirst) {
+            return DESC_NULLS_FIRST;
+        } else {
+            return DESC_NULLS_LAST;
+        }
+    }
+
+    /** Returns whether the column sorted in ascending order. */
+    public boolean asc() {
+        return asc;
+    }
+
+    /** Returns whether null values should be in the very beginning of the 
range. */
+    public boolean nullsFirst() {
+        return nullsFirst;
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/HashIndexDescriptor.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/HashIndexDescriptor.java
new file mode 100644
index 0000000000..8e2d96c3da
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/HashIndexDescriptor.java
@@ -0,0 +1,64 @@
+/*
+ * 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.catalog.descriptors;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import org.apache.ignite.internal.tostring.S;
+
+/**
+ * Hash index descriptor.
+ */
+public class HashIndexDescriptor extends IndexDescriptor {
+    private static final long serialVersionUID = -6784028115063219759L;
+
+    private final List<String> columns;
+
+    /**
+     * Constructs a hash index descriptor.
+     *
+     * @param id Id of the index.
+     * @param name Name of the index.
+     * @param tableId Id of the table index belongs to.
+     * @param columns A list of indexed columns. Must not contains duplicates.
+     * @throws IllegalArgumentException If columns list contains duplicates.
+     */
+    public HashIndexDescriptor(int id, String name, int tableId, List<String> 
columns) {
+        super(id, name, tableId, true);
+
+        this.columns = List.copyOf(Objects.requireNonNull(columns, "columns"));
+
+        if (new HashSet<>(columns).size() != columns.size()) {
+            throw new IllegalArgumentException("Indexed columns should be 
unique");
+        }
+    }
+
+    /** Returns indexed columns. */
+    public List<String> columns() {
+        return columns;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return S.toString(this);
+    }
+}
+
+
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/IndexColumnDescriptor.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/IndexColumnDescriptor.java
new file mode 100644
index 0000000000..621000152f
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/IndexColumnDescriptor.java
@@ -0,0 +1,52 @@
+/*
+ * 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.catalog.descriptors;
+
+import java.io.Serializable;
+import java.util.Objects;
+import org.apache.ignite.internal.tostring.S;
+
+/**
+ * Indexed column descriptor.
+ */
+public class IndexColumnDescriptor implements Serializable {
+    private static final long serialVersionUID = 5750677168056750717L;
+
+    private final String name;
+
+    private final ColumnCollation collation;
+
+    public IndexColumnDescriptor(String name, ColumnCollation collation) {
+        this.name = name;
+        this.collation = Objects.requireNonNull(collation, "collation");
+    }
+
+    public String name() {
+        return name;
+    }
+
+    public ColumnCollation collation() {
+        return collation;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return S.toString(this);
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/IndexDescriptor.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/IndexDescriptor.java
new file mode 100644
index 0000000000..99feaf15e3
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/IndexDescriptor.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.ignite.internal.catalog.descriptors;
+
+import org.apache.ignite.internal.tostring.S;
+
+/**
+ * Index descriptor base class.
+ */
+public abstract class IndexDescriptor extends ObjectDescriptor {
+    private static final long serialVersionUID = -8045949593661301287L;
+
+    /** Table id. */
+    private final int tableId;
+
+    /** Unique constraint flag. */
+    private boolean unique;
+
+    /** Write only flag. {@code True} when index is building. */
+    private boolean writeOnly;
+
+    IndexDescriptor(int id, String name, int tableId, boolean unique) {
+        super(id, Type.INDEX, name);
+        this.tableId = tableId;
+        this.unique = unique;
+    }
+
+    public int tableId() {
+        return tableId;
+    }
+
+    public boolean unique() {
+        return unique;
+    }
+
+    public boolean writeOnly() {
+        return writeOnly;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return S.toString(this);
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/ObjectDescriptor.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/ObjectDescriptor.java
new file mode 100644
index 0000000000..eabd9e5dff
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/ObjectDescriptor.java
@@ -0,0 +1,62 @@
+/*
+ * 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.catalog.descriptors;
+
+import java.io.Serializable;
+import java.util.Objects;
+import org.apache.ignite.internal.tostring.S;
+
+/**
+ * Base class for catalog objects.
+ * TODO: IGNITE-18535 Implement custom effective serialization instead.
+ */
+public abstract class ObjectDescriptor implements Serializable {
+    private static final long serialVersionUID = -6525237234280004860L;
+    private final int id;
+    private final String name;
+    private final Type type;
+
+    ObjectDescriptor(int id, Type type, String name) {
+        this.id = id;
+        this.type = Objects.requireNonNull(type, "type");
+        this.name = Objects.requireNonNull(name, "name");
+    }
+
+    /** Returns id of the described object. */
+    public int id() {
+        return id;
+    }
+
+    /** Returns name of the described object. */
+    public String name() {
+        return name;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return S.toString(this);
+    }
+
+    /** Catalog object type. */
+    enum Type {
+        SCHEMA,
+        TABLE,
+        INDEX
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/SchemaDescriptor.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/SchemaDescriptor.java
new file mode 100644
index 0000000000..4a4c53736f
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/SchemaDescriptor.java
@@ -0,0 +1,90 @@
+/*
+ * 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.catalog.descriptors;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.tostring.IgniteToStringExclude;
+import org.apache.ignite.internal.tostring.S;
+
+/**
+ * Schema definition contains database schema objects.
+ */
+public class SchemaDescriptor extends ObjectDescriptor {
+    private static final long serialVersionUID = -233494425779955410L;
+
+    private final int version;
+    private final TableDescriptor[] tables;
+    private final IndexDescriptor[] indexes;
+
+    @IgniteToStringExclude
+    private transient Map<String, TableDescriptor> tablesMap;
+    @IgniteToStringExclude
+    private transient Map<String, IndexDescriptor> indexesMap; //TODO: 
IGNITE-18535 Drop if not used.
+
+    public SchemaDescriptor(int id, String name, int version, 
TableDescriptor[] tables, IndexDescriptor[] indexes) {
+        super(id, Type.SCHEMA, name);
+        this.version = version;
+        this.tables = Objects.requireNonNull(tables, "tables");
+        this.indexes = Objects.requireNonNull(indexes, "indexes");
+
+        rebuildMaps();
+    }
+
+    public int version() {
+        return version;
+    }
+
+    TableDescriptor[] tables() {
+        return tables;
+    }
+
+    IndexDescriptor[] indexes() {
+        return indexes;
+    }
+
+    public TableDescriptor table(String name) {
+        return tablesMap.get(name);
+    }
+
+    public IndexDescriptor index(String name) {
+        return indexesMap.get(name);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, 
ClassNotFoundException {
+        in.defaultReadObject();
+
+        rebuildMaps();
+    }
+
+    private void rebuildMaps() {
+        tablesMap = 
Arrays.stream(tables).collect(Collectors.toMap(ObjectDescriptor::name, 
Function.identity()));
+        indexesMap = 
Arrays.stream(indexes).collect(Collectors.toMap(ObjectDescriptor::name, 
Function.identity()));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return S.toString(this);
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/SortedIndexDescriptor.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/SortedIndexDescriptor.java
new file mode 100644
index 0000000000..cfc59ee4c4
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/SortedIndexDescriptor.java
@@ -0,0 +1,59 @@
+/*
+ * 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.catalog.descriptors;
+
+
+import java.util.List;
+import java.util.Objects;
+import org.apache.ignite.internal.tostring.S;
+
+/**
+ * Sorted index descriptor.
+ */
+public class SortedIndexDescriptor extends IndexDescriptor {
+    private static final long serialVersionUID = 2085714310150728611L;
+
+    private final List<IndexColumnDescriptor> columns;
+
+    /**
+     * Constructs a sorted description.
+     *
+     * @param id Id of the index.
+     * @param name Name of the index.
+     * @param tableId Id of the table index belongs to.
+     * @param columns A list of columns descriptors.
+     * @throws IllegalArgumentException If columns list contains duplicates or 
columns size doesn't match the collations size.
+     */
+    public SortedIndexDescriptor(int id, String name, int tableId, 
List<IndexColumnDescriptor> columns) {
+        super(id, name, tableId, false);
+
+        this.columns = Objects.requireNonNull(columns, "columns");
+    }
+
+    public List<IndexColumnDescriptor> columns() {
+        return columns;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return S.toString(this);
+    }
+}
+
+
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/TableColumnDescriptor.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/TableColumnDescriptor.java
new file mode 100644
index 0000000000..4a7d9aeb60
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/TableColumnDescriptor.java
@@ -0,0 +1,75 @@
+/*
+ * 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.catalog.descriptors;
+
+import java.io.Serializable;
+import java.util.Objects;
+import org.apache.ignite.internal.tostring.S;
+import org.apache.ignite.sql.ColumnType;
+
+/**
+ * Table column descriptor.
+ */
+public class TableColumnDescriptor implements Serializable {
+    private static final long serialVersionUID = 7684890562398520509L;
+
+    private final String name;
+    private final ColumnType type;
+    private final boolean nullable;
+    /** Max length constraint. */
+    private int length;
+    private int precision;
+    private int scale;
+    private String defaultValueExpression;
+
+    public TableColumnDescriptor(String name, ColumnType type, boolean 
nullable) {
+        this.name = Objects.requireNonNull(name, "name");
+        this.type = Objects.requireNonNull(type);
+        this.nullable = nullable;
+    }
+
+    public String name() {
+        return name;
+    }
+
+    public boolean nullable() {
+        return nullable;
+    }
+
+    public ColumnType type() {
+        return type;
+    }
+
+    public int precision() {
+        return precision;
+    }
+
+    public int scale() {
+        return scale;
+    }
+
+    public int length() {
+        return length;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return S.toString(this);
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/TableDescriptor.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/TableDescriptor.java
new file mode 100644
index 0000000000..6babceaf33
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/descriptors/TableDescriptor.java
@@ -0,0 +1,86 @@
+/*
+ * 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.catalog.descriptors;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.tostring.IgniteToStringExclude;
+import org.apache.ignite.internal.tostring.S;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Table descriptor.
+ */
+public class TableDescriptor extends ObjectDescriptor {
+    private static final long serialVersionUID = -2021394971104316570L;
+
+    private final int zoneId = 0;
+    private final int engineId = 0;
+
+    private final TableColumnDescriptor[] columns;
+    private final String[] primaryKeyColumns;
+    private final String[] colocationColumns;
+
+    @IgniteToStringExclude
+    private transient Map<String, TableColumnDescriptor> columnsMap;
+
+    public TableDescriptor(int id, String name, TableColumnDescriptor[] 
columns, String[] pkCols, @Nullable String[] colocationCols) {
+        super(id, Type.TABLE, name);
+
+        this.columns = Objects.requireNonNull(columns);
+        primaryKeyColumns = Objects.requireNonNull(pkCols, "No primary key 
columns.");
+        colocationColumns = Objects.requireNonNullElse(colocationCols, 
primaryKeyColumns);
+
+        this.columnsMap = 
Arrays.stream(columns).collect(Collectors.toMap(TableColumnDescriptor::name, 
Function.identity()));
+
+        // TODO: IGNITE-18535 Throw proper exceptions.
+        assert !columnsMap.isEmpty() : "No columns.";
+        assert primaryKeyColumns.length > 0 : "No primary key columns.";
+        assert colocationColumns.length > 0 : "No colocation columns.";
+
+        assert Arrays.stream(primaryKeyColumns).noneMatch(c -> 
Objects.requireNonNull(columnsMap.get(c), c).nullable());
+        //noinspection ArrayEquality
+        assert primaryKeyColumns == colocationColumns || 
Set.of(primaryKeyColumns).containsAll(List.of(colocationColumns));
+    }
+
+    public int zoneId() {
+        return zoneId;
+    }
+
+    public int engineId() {
+        return engineId;
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, 
ClassNotFoundException {
+        in.defaultReadObject();
+        this.columnsMap = 
Arrays.stream(columns).collect(Collectors.toMap(TableColumnDescriptor::name, 
Function.identity()));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return S.toString(this);
+    }
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/CatalogEvent.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/CatalogEvent.java
new file mode 100644
index 0000000000..366c4858d1
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/CatalogEvent.java
@@ -0,0 +1,26 @@
+/*
+ * 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.catalog.events;
+
+import org.apache.ignite.internal.manager.Event;
+
+/**
+ * TODO: IGNITE-18535 Javadoc.
+ */
+public enum CatalogEvent implements Event {
+}
diff --git 
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/CatalogEventParameters.java
 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/CatalogEventParameters.java
new file mode 100644
index 0000000000..6b974c4a72
--- /dev/null
+++ 
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/events/CatalogEventParameters.java
@@ -0,0 +1,34 @@
+/*
+ * 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.catalog.events;
+
+import org.apache.ignite.internal.manager.EventParameters;
+
+/**
+ * TODO: IGNITE-18535 Javadoc.
+ */
+public class CatalogEventParameters extends EventParameters {
+    /**
+     * Constructor.
+     *
+     * @param causalityToken Causality token.
+     */
+    public CatalogEventParameters(long causalityToken) {
+        super(causalityToken);
+    }
+}
diff --git a/settings.gradle b/settings.gradle
index ca9b7f3ba7..f33fd8d336 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -67,6 +67,7 @@ include(':ignite-distribution-zones')
 include(':ignite-placement-driver')
 include(':ignite-code-deployment')
 include(':ignite-security')
+include(':ignite-catalog')
 
 project(":ignite-examples").projectDir = file('examples')
 project(":ignite-page-memory").projectDir = file('modules/page-memory')
@@ -119,6 +120,7 @@ project(":ignite-distribution-zones").projectDir = 
file('modules/distribution-zo
 project(":ignite-placement-driver").projectDir = 
file('modules/placement-driver')
 project(":ignite-code-deployment").projectDir = file('modules/code-deployment')
 project(":ignite-security").projectDir = file('modules/security')
+project(":ignite-catalog").projectDir = file('modules/catalog')
 
 ext.isCiServer = System.getenv().containsKey("IGNITE_CI")
 


Reply via email to