All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.tarantool.driver.core.metadata.TarantoolMetadata Maven / Gradle / Ivy

Go to download

Tarantool Cartridge driver for Tarantool versions 1.10+ based on Netty framework

There is a newer version: 0.14.0
Show newest version
package io.tarantool.driver.core.metadata;

import io.tarantool.driver.api.metadata.TarantoolIndexMetadata;
import io.tarantool.driver.api.metadata.TarantoolMetadataOperations;
import io.tarantool.driver.api.metadata.TarantoolMetadataProvider;
import io.tarantool.driver.api.metadata.TarantoolSpaceMetadata;
import io.tarantool.driver.exceptions.TarantoolClientException;
import io.tarantool.driver.exceptions.TarantoolNoSuchProcedureException;
import io.tarantool.driver.utils.Assert;

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Phaser;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Base class for {@link TarantoolMetadataOperations} implementations
 *
 * @author Alexey Kuzin
 */
public class TarantoolMetadata implements TarantoolMetadataOperations {

    protected final Map spaceMetadataByName = new ConcurrentHashMap<>();
    protected final Map spaceMetadataById = new ConcurrentHashMap<>();
    protected final Map> indexMetadataBySpaceName =
        new ConcurrentHashMap<>();
    protected final Map> indexMetadataBySpaceId =
        new ConcurrentHashMap<>();
    private final Phaser initPhaser = new Phaser(0);
    private final AtomicBoolean needRefresh = new AtomicBoolean(true);
    private final TarantoolMetadataProvider metadataProvider;

    public TarantoolMetadata(TarantoolMetadataProvider metadataProvider) {
        this.metadataProvider = metadataProvider;
    }

    protected Map getSpaceMetadata() {
        awaitInitLatch();
        return spaceMetadataByName;
    }

    protected Map getSpaceMetadataById() {
        awaitInitLatch();
        return spaceMetadataById;
    }

    protected Map> getIndexMetadata() {
        awaitInitLatch();
        return indexMetadataBySpaceName;
    }

    protected Map> getIndexMetadataBySpaceId() {
        awaitInitLatch();
        return indexMetadataBySpaceId;
    }

    @Override
    public void scheduleRefresh() {
        needRefresh.set(true);
    }

    @Override
    public CompletableFuture refresh() throws TarantoolClientException {
        return populateMetadata().whenComplete((v, ex) -> {
            if (ex != null) {
                needRefresh.set(true);
            }
            initPhaser.arriveAndDeregister();
        });
    }

    private void awaitInitLatch() {
        if (initPhaser.getRegisteredParties() == 0 && needRefresh.compareAndSet(true, false)) {
            initPhaser.register();
            try {
                refresh().get();
            } catch (InterruptedException e) {
                throw new TarantoolClientException("Failed to refresh spaces and indexes metadata", e);
            } catch (ExecutionException e) {
                Throwable cause = e.getCause();
                if (cause instanceof TarantoolNoSuchProcedureException) {
                    //This case is required to handle retry when instances are not initialized yet.
                    //See https://github.com/tarantool/cartridge-java/issues/170
                    throw (TarantoolNoSuchProcedureException) cause;
                }
                throw new TarantoolClientException("Failed to refresh spaces and indexes metadata", cause);
            }
        } else {
            initPhaser.awaitAdvance(initPhaser.getPhase());
        }
    }

    private CompletableFuture populateMetadata() {
        CompletableFuture result = new CompletableFuture<>();
        try {
            result = metadataProvider.getMetadata().thenAccept(container -> {
                spaceMetadataByName.clear();
                spaceMetadataById.clear();
                indexMetadataBySpaceName.clear();
                indexMetadataBySpaceId.clear();

                indexMetadataBySpaceName.putAll(container.getIndexMetadataBySpaceName());
                container.getSpaceMetadataByName().forEach((spaceName, spaceMetadata) -> {
                    spaceMetadataByName.put(spaceName, spaceMetadata);
                    spaceMetadataById.put(spaceMetadata.getSpaceId(), spaceMetadata);
                    Map indexesForSpace =
                        indexMetadataBySpaceName.get(spaceMetadata.getSpaceName());
                    if (indexesForSpace != null) {
                        indexMetadataBySpaceId.put(spaceMetadata.getSpaceId(), indexesForSpace);
                    }
                });
            });
        } catch (Throwable e) {
            result.completeExceptionally(e);
        }
        return result;
    }

    @Override
    public Optional getSpaceByName(String spaceName) {
        Assert.hasText(spaceName, "Space name must not be null or empty");

        return Optional.ofNullable(getSpaceMetadata().get(spaceName));
    }

    @Override
    public Optional getIndexByName(int spaceId, String indexName) {
        Assert.state(spaceId > 0, "Space ID must be greater than 0");
        Assert.hasText(indexName, "Index name must not be null or empty");

        Map metaMap = getIndexMetadataBySpaceId().get(spaceId);
        if (metaMap == null) {
            return Optional.empty();
        }
        return Optional.ofNullable(metaMap.get(indexName));
    }

    @Override
    public Optional getIndexByName(String spaceName, String indexName) {
        Assert.hasText(spaceName, "Space name must not be null or empty");
        Assert.hasText(indexName, "Index name must not be null or empty");

        Map metaMap = getIndexMetadata().get(spaceName);
        if (metaMap == null) {
            return Optional.empty();
        }

        return Optional.ofNullable(metaMap.get(indexName));
    }

    @Override
    public Optional getIndexById(String spaceName, int indexId) {
        Assert.hasText(spaceName, "Space name must not be null or empty");
        Assert.state(indexId >= 0, "Index ID must be greater than or equal 0");

        Map metaMap = getIndexMetadata().get(spaceName);
        if (metaMap == null) {
            return Optional.empty();
        }

        return metaMap.values().stream().filter(i -> i.getIndexId() == indexId).findFirst();
    }

    @Override
    public Optional getIndexById(int spaceId, int indexId) {
        Assert.state(spaceId > 0, "Space ID must be greater than 0");
        Assert.state(indexId >= 0, "Index ID must be greater than or equal 0");

        Map metaMap = getIndexMetadataBySpaceId().get(spaceId);
        if (metaMap == null) {
            return Optional.empty();
        }

        return metaMap.values().stream().filter(i -> i.getIndexId() == indexId).findFirst();
    }

    @Override
    public Optional getSpaceById(int spaceId) {
        Assert.state(spaceId > 0, "Space ID must be greater than 0");

        return Optional.ofNullable(getSpaceMetadataById().get(spaceId));
    }

    @Override
    public Optional> getSpaceIndexes(int spaceId) {
        Assert.state(spaceId > 0, "Space ID must be greater than 0");

        return Optional.ofNullable(getIndexMetadataBySpaceId().get(spaceId));
    }

    @Override
    public Optional> getSpaceIndexes(String spaceName) {
        Assert.hasText(spaceName, "Space name must not be null or empty");

        return Optional.ofNullable(getIndexMetadata().get(spaceName));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy