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

com.tangosol.persistence.ArchiverHelper Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */
package com.tangosol.persistence;

import com.tangosol.net.CacheFactory;

import com.tangosol.util.Base;

import java.io.File;
import java.io.FileFilter;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * Various helper methods for the archiver functionality.
 *
 * @since  12.2.1
 * @author tam  2014.03.18
 * @deprecated this API is intended for internal purposes only and will be removed
 *             in a future version of Coherence
 */
@Deprecated
// Internal Notes: THIS IMPLEMENTATION HAS BEEN ABANDONED AS OF 12.2.1.2
public class ArchiverHelper
    {
    /**
     * Given a {@link Map} of member Id's and the stores each member can see
     * for a given snapshot, allocate the stores evenly as so to allow the
     * archival process to run in parallel across the greatest number of
     * members. Each member may see the same stores, as they may be on
     * shared disk or on the same machine.
     *
     * @param mapStores    a {@link Map} of members and {@link Object[]}s
     *                     that need sorting and allocating
     * @param cPartitions  the number of partitions
     *
     */
    public static void allocateSnapshotPartitions(Map mapStores, int cPartitions)
        {
        try
            {
            if (mapStores == null || mapStores.size() == 0)
                {
                throw new IllegalArgumentException("You must supply a collected map of partitions");
                }

            int      nMemberCount = mapStores.size();
            String[] asStoresAll  = getDistinctStores(mapStores);

            if (asStoresAll.length != cPartitions)
                {
                String sMessage = "Number of unique stores is " + asStoresAll.length
                                + " and does not match partition count of " + cPartitions
                                + ". This means that some stores are missing or the snapshot is corrupted.";
                CacheFactory.log(sMessage, CacheFactory.LOG_ERR);

                CacheFactory.log("Dumping distinct store list because of error", CacheFactory.LOG_WARN);
                for (String sStore : asStoresAll)
                    {
                    CacheFactory.log(sStore,CacheFactory.LOG_WARN);
                    }

                throw new IllegalArgumentException(sMessage);
                }

            // check for the special case where all members see the same partitions,
            // e.g. shared disk
            boolean fSharedPartitions = true;

            for (Map.Entry entry : mapStores.entrySet())
                {
                Object[] asSorted = entry.getValue();

                if (asSorted != null)
                    {
                    Arrays.sort(asSorted);
                    }

                if (!Arrays.equals(asSorted, asStoresAll))
                    {
                    fSharedPartitions = false;
                    break;
                    }
                }

            if (fSharedPartitions)
                {
                // work out a fair share and allocate to all
                int nFairShare        = cPartitions / nMemberCount;
                int nPartitionStart   = 0;
                int nEntriesProcessed = 0;

                for (Iterator> iter = mapStores.entrySet().iterator(); iter.hasNext();)
                    {
                    Map.Entry entry = iter.next();
                    nEntriesProcessed++;

                    int nLastPartition = nEntriesProcessed < nMemberCount ? (nPartitionStart + nFairShare - 1) : cPartitions - 1;
                    String[]  asStores = new String[nLastPartition - nPartitionStart + 1];

                    for (int i = nPartitionStart, j = 0; i <= nLastPartition; i++)
                        {
                        asStores[j++] = asStoresAll[i];
                        }

                    mapStores.put(entry.getKey(), asStores);
                    nPartitionStart += nFairShare;
                    }
                }
            else
                {
                // partitions are distributed amongst all members with some potential
                // duplicates. Remove the duplicates trying to keep it as balanced as possible

                // go through each store and see if the store is known to more than 1 member
                for (int iPart = 0; iPart < cPartitions; iPart++)
                    {
                    Set setMembers = getMembersOwningPartition(mapStores, asStoresAll[iPart]);

                    // keep reducing the members that know about this partition to 1 while trying to keep balanced
                    while (setMembers.size() > 1)
                        {
                        // find the member that has the most partitions allocated and remove the partition from it
                        int nMemberMaxPartitions = -1;
                        int nMaxPartitions       = -1;

                        for (Integer nMember : setMembers)
                            {
                            int nMax = mapStores.get(nMember).length;

                            if (nMax > nMaxPartitions)
                                {
                                nMaxPartitions       = nMax;
                                nMemberMaxPartitions = nMember;
                                }
                            }

                        // the member nMemberMaxPartitions will have the partition "iPart" removed
                        Object[] aoStores = mapStores.get(nMemberMaxPartitions);

                        // remove the store from this array
                        mapStores.put(nMemberMaxPartitions, removeStoreFromArray(asStoresAll[iPart], aoStores));

                        // re-query the set again
                        setMembers = getMembersOwningPartition(mapStores, asStoresAll[iPart]);
                        }
                    }
                }
            }
        catch (Exception e)
            {
            throw Base.ensureRuntimeException(e, "Error in ArchiverHelper.allocateSnapshotPartitions");
            }
        }

    /**
     * Return the {@link Set} of members who are aware of a particular
     * store.
     *
     * @param mapStores  the {@link Map} of discovered partitions for members
     * @param sStore     the store we are interested in
     *
     * @return  the {@link Set} of members who are aware of a particular store
     */
    public static Set getMembersOwningPartition(Map mapStores, String sStore)
        {
        Set setMembers = new HashSet<>();

        for (Map.Entry entry : mapStores.entrySet())
            {
            Object[] aoValue = entry.getValue();
            if (aoValue != null)
                {
                for (int i = 0; i < aoValue.length; i++)
                    {
                    if (sStore.equals(aoValue[i]))
                        {
                        setMembers.add(entry.getKey());
                        break;
                        }
                    }
                }
            }

        return setMembers;
        }

    // ----- helpers --------------------------------------------------------

    /**
     * Return a a sorted array of distinct stores
     *
     * @param mapStores the {@link Map} of discovered partitions for members
     *
     * @return a {@link String[]} of distinct stores
     */
    private static String[] getDistinctStores(Map mapStores)
        {
        Set setStores = new HashSet<>();

        for (Map.Entry entry : mapStores.entrySet())
            {
            Object[] aoValue = entry.getValue();

            if (aoValue != null)
                {
                for (int i = 0; i < aoValue.length; i++)
                    {
                    String sStore = (String) aoValue[i];
                    if (!setStores.contains(sStore))
                        {
                        setStores.add(sStore);
                        }
                    }
                }
            }

        String[] asResults = setStores.toArray(new String[setStores.size()]);

        Arrays.sort(asResults);

        return asResults;
        }

    /**
     * Remove the given store from the array and return a new array.
     *
     * @param sStoreToRemove the store to remove
     * @param aoArray        the array to remove from
     *
     * @return the new array with the store removed
     */
    private static Object[] removeStoreFromArray(String sStoreToRemove, Object[] aoArray)
        {
        Object[] aoNewArray = new Object[aoArray.length - 1];

        for (int i = 0, j = 0; j < aoArray.length; j++)
            {
            String sStore = (String) aoArray[j];
            if (!sStore.equals(sStoreToRemove))
                {
                aoNewArray[i++] = sStore;
                }
            }
        return aoNewArray;
        }

    // ----- inner class: DirectoryFileFilter -------------------------------

    /**
     * FileFilter implementation that only includes directories.
     */
    public static class DirectoryFileFilter
            implements FileFilter
        {
        /**
         * Accept the given file only if it is a directory.
         *
         * @param file the file
         *
         * @return true if the given file is a directory
         */
        @Override
        public boolean accept(File file)
            {
            return file.isDirectory();
            }

        /**
         * Singleton instance.
         */
        public static final FileFilter INSTANCE = new DirectoryFileFilter();
        }
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy