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

de.zalando.sprocwrapper.dsprovider.BitmapShardDataSourceProvider Maven / Gradle / Ivy

Go to download

Library to make PostgreSQL stored procedures available through simple Java "*SProcService" interfaces including automatic object serialization and deserialization (using typemapper and convention-over-configuration). Supports sharding, advisory locking, statement timeouts and PostgreSQL types such as enums and hstore.

There is a newer version: 2.0.0
Show newest version
package de.zalando.sprocwrapper.dsprovider;

import java.lang.reflect.InvocationTargetException;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.sql.DataSource;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

public class BitmapShardDataSourceProvider implements DataSourceProvider {

    private static final Logger LOG = LoggerFactory.getLogger(BitmapShardDataSourceProvider.class);

    private final DataSource[] dataSources;

    private final int mask;

    private final List distinctShardIds;

    public BitmapShardDataSourceProvider(final Map connectionDataSources) {

        int maskLength = 0;
        for (Entry entry : connectionDataSources.entrySet()) {
            if (entry.getKey().length() > maskLength) {
                maskLength = entry.getKey().length();
            }
        }

        mask = (1 << maskLength) - 1;

        dataSources = new DataSource[1 << maskLength];

        for (Entry entry : connectionDataSources.entrySet()) {
            DataSource ds = entry.getValue();

            for (int i = 0; i < dataSources.length; i++) {
                String binaryString = StringUtils.repeat("0", maskLength) + Integer.toBinaryString(i);
                if (binaryString.endsWith(entry.getKey())) {
                    LOG.debug("Configured {} at index {}", entry.getValue(), i);
                    if (dataSources[i] != null) {
                        throw new IllegalArgumentException(
                            "Bitmask misconfigured for shards: two connections configured for index " + i);
                    }

                    dataSources[i] = ds;
                }
            }
        }

        for (int i = 0; i < dataSources.length; i++) {
            if (dataSources[i] == null) {
                throw new IllegalArgumentException("Not enough connection URLs configured for mask length " + maskLength
                        + ": datasource at index " + i + " is missing");
            }
        }

        distinctShardIds = Lists.newArrayList();

        Set seenDataSources = Sets.newHashSet();

        for (int i = 0; i < dataSources.length; i++) {
            if (!seenDataSources.contains(dataSources[i])) {
                distinctShardIds.add(i);
                seenDataSources.add(dataSources[i]);
            }
        }
    }

    public BitmapShardDataSourceProvider(final Class dataSourceClass,
            final Map commonDataSourceProperties, final Map connectionUrls)
        throws InstantiationException, IllegalAccessException, InvocationTargetException {

        int maskLength = 0;
        for (Entry entry : connectionUrls.entrySet()) {
            if (entry.getKey().length() > maskLength) {
                maskLength = entry.getKey().length();
            }
        }

        mask = (1 << maskLength) - 1;
        dataSources = new DataSource[1 << maskLength];

        for (Entry entry : connectionUrls.entrySet()) {
            DataSource ds = dataSourceClass.newInstance();
            for (Entry prop : commonDataSourceProperties.entrySet()) {
                BeanUtils.setProperty(ds, prop.getKey(), prop.getValue());
            }

            String[] parts = entry.getValue().split("\\|");

            BeanUtils.setProperty(ds, "jdbcUrl", parts[0]);

            if (parts.length > 1) {

                // a little bit hacky, because "initSQL" is boneCP-specific
                BeanUtils.setProperty(ds, "initSQL", parts[1]);
            }

            for (int i = 0; i < dataSources.length; i++) {
                String binaryString = StringUtils.repeat("0", maskLength) + Integer.toBinaryString(i);
                if (binaryString.endsWith(entry.getKey())) {
                    LOG.debug("Configured " + entry.getValue() + " at index " + i);
                    if (dataSources[i] != null) {
                        throw new IllegalArgumentException(
                            "Bitmask misconfigured for shards: two connections configured for index " + i);
                    }

                    dataSources[i] = ds;
                }
            }
        }

        for (int i = 0; i < dataSources.length; i++) {
            if (dataSources[i] == null) {
                throw new IllegalArgumentException("Not enough connection URLs configured for mask length " + maskLength
                        + ": datasource at index " + i + " is missing");
            }
        }

        distinctShardIds = Lists.newArrayList();

        Set seenDataSources = Sets.newHashSet();

        for (int i = 0; i < dataSources.length; i++) {
            if (!seenDataSources.contains(dataSources[i])) {
                distinctShardIds.add(i);
                seenDataSources.add(dataSources[i]);
            }
        }

    }

    @Override
    public int getDataSourceId(final int virtualShardId) {
        return virtualShardId & mask;
    }

    @Override
    public DataSource getDataSource(final int virtualShardId) {
        return dataSources[virtualShardId & mask];
    }

    @Override
    public List getDistinctShardIds() {
        return distinctShardIds;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy