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

com.tangosol.internal.util.DefaultAsyncNamedCache Maven / Gradle / Ivy

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

import com.oracle.coherence.common.util.Options;

import com.tangosol.internal.util.processor.CacheProcessors;

import com.tangosol.net.AsyncNamedCache;
import com.tangosol.net.CacheService;
import com.tangosol.net.Member;
import com.tangosol.net.NamedCache;
import com.tangosol.net.NamedMap;
import com.tangosol.net.PartitionedService;
import com.tangosol.net.partition.PartitionSet;

import com.tangosol.util.Filter;
import com.tangosol.util.InvocableMap;
import com.tangosol.util.InvocableMap.StreamingAggregator;
import com.tangosol.util.aggregator.AsynchronousAggregator;
import com.tangosol.util.filter.PartitionedFilter;
import com.tangosol.util.processor.AsynchronousProcessor;
import com.tangosol.util.processor.SingleEntryAsynchronousProcessor;
import com.tangosol.util.processor.StreamingAsynchronousProcessor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import java.util.concurrent.CompletableFuture;

import java.util.function.Consumer;

/**
 * Default implementation of the {@link AsyncNamedCache} API.
 *
 * @author as  2015.01.15
 */
public class DefaultAsyncNamedCache
        implements AsyncNamedCache
    {
    // ---- constructors ----------------------------------------------------

    /**
     * Construct DefaultAsyncNamedCache instance.
     *
     * @param cache  the wrapped NamedCache to delegate invocations to
     */
    public DefaultAsyncNamedCache(NamedCache cache)
        {
        // NOTE: while not strictly required any longer, we need to keep this
        // constructor in order to preserve binary compatibility with 12.2.1.0.0
        this(cache, null);
        }

    /**
     * Construct DefaultAsyncNamedCache instance.
     *
     * @param cache    the wrapped NamedCache to delegate invocations to
     * @param options  the configuration options
     */
    public DefaultAsyncNamedCache(NamedCache cache, AsyncNamedCache.Option[] options)
        {
        m_cache   = cache;
        m_options = Options.from(AsyncNamedCache.Option.class, options);
        }

    // ---- AsyncNamedCache interface ---------------------------------------

    @Override
    public NamedCache getNamedCache()
        {
        return m_cache;
        }

    // ---- AsyncNamedMap interface -----------------------------------------

    @Override
    public NamedMap getNamedMap()
        {
        return m_cache;
        }

    @Override
    public CompletableFuture>> entrySet(Filter filter)
        {
        // optimized implementation that runs query against individual partitions
        // in parallel and aggregates the results

        if (m_cache.getCacheService() instanceof PartitionedService && !(filter instanceof PartitionedFilter))
            {
            int          cParts = ((PartitionedService) m_cache.getCacheService()).getPartitionCount();
            PartitionSet parts  = new PartitionSet(cParts);

            List>>> futures = new ArrayList<>(cParts);

            for (int i = 0; i < cParts; i++)
                {
                parts.add(i);
                futures.add(invokeAll(new PartitionedFilter<>(filter, parts), new AsynchronousProcessor<>(CacheProcessors.binaryGet(), i))
                        .thenApply(Map::entrySet));
                parts.remove(i);
                }

            CompletableFuture>> result = new CompletableFuture<>();
            CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new))
                    .whenComplete((v, err) ->
                        {
                        if (err != null)
                            {
                            result.completeExceptionally(err);
                            }
                        else
                            {
                            Set> set = new HashSet<>();
                            futures.forEach(f -> f.thenAccept(set::addAll));
                            result.complete(set);
                            }
                    });

            return result;
            }
        else
            {
            return AsyncNamedCache.super.entrySet(filter);
            }
        }

    @Override
    public CompletableFuture entrySet(Filter filter, Consumer> callback)
        {
        // optimized implementation that runs query against individual partitions
        // in parallel and aggregates the results

        if (m_cache.getCacheService() instanceof PartitionedService && !(filter instanceof PartitionedFilter))
            {
            int          cParts  = ((PartitionedService) m_cache.getCacheService()).getPartitionCount();
            PartitionSet parts   = new PartitionSet(cParts);

            List> futures = new ArrayList<>(cParts);

            for (int i = 0; i < cParts; i++)
                {
                parts.add(i);
                futures.add(invokeAll(new PartitionedFilter<>(filter, parts),
                                      new StreamingAsynchronousProcessor<>(CacheProcessors.binaryGet(), i, callback),
                                      callback)); // needed to ensure the streaming invokeAll is called!
                parts.remove(i);
                }

            return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new));
            }
        else
            {
            return AsyncNamedCache.super.entrySet(filter, callback);
            }
        }

    // ---- AsyncInvocableMap interface -------------------------------------

    @Override
    public  CompletableFuture invoke(K key,
                                InvocableMap.EntryProcessor processor)
        {
        SingleEntryAsynchronousProcessor asyncProcessor =
                instantiateSingleEntryAsyncProcessor(processor);

        m_cache.invoke(key, asyncProcessor);

        return asyncProcessor.getCompletableFuture();
        }

    @Override
    public  CompletableFuture> invokeAll(Collection collKeys,
                                                      InvocableMap.EntryProcessor processor)
        {
        AsynchronousProcessor asyncProcessor =
                instantiateMultiEntryAsyncProcessor(processor);

        m_cache.invokeAll(collKeys, asyncProcessor);

        return asyncProcessor.getCompletableFuture();
        }

    @Override
    public  CompletableFuture> invokeAll(Filter filter,
                                           InvocableMap.EntryProcessor processor)
        {
        AsynchronousProcessor asyncProcessor =
                instantiateMultiEntryAsyncProcessor(processor);

        m_cache.invokeAll(filter, asyncProcessor);

        return asyncProcessor.getCompletableFuture();
        }

    @Override
    public  CompletableFuture invokeAll(Collection collKeys,
                                                 InvocableMap.EntryProcessor processor,
                                                 Consumer> callback)
        {
        StreamingAsynchronousProcessor asyncProcessor =
                instantiateStreamingAsyncProcessor(processor, callback);

        m_cache.invokeAll(collKeys, asyncProcessor);

        return asyncProcessor.getCompletableFuture();
        }

    @Override
    public  CompletableFuture invokeAll(Filter filter,
                                                 InvocableMap.EntryProcessor processor,
                                                 Consumer> callback)
        {
        StreamingAsynchronousProcessor asyncProcessor =
                instantiateStreamingAsyncProcessor(processor, callback);

        m_cache.invokeAll(filter, asyncProcessor);

        return asyncProcessor.getCompletableFuture();
        }

    @Override
    public  CompletableFuture aggregate(
            Collection collKeys, InvocableMap.EntryAggregator aggregator)
        {
        AsynchronousAggregator asyncAggregator =
                instantiateAsyncAggregator(aggregator);

        m_cache.aggregate(collKeys, asyncAggregator);

        return asyncAggregator.getCompletableFuture();
        }

    @Override
    public  CompletableFuture aggregate(
            Filter filter, InvocableMap.EntryAggregator aggregator)
        {
        AsynchronousAggregator asyncAggregator =
                instantiateAsyncAggregator(aggregator);

        m_cache.aggregate(filter, asyncAggregator);

        return asyncAggregator.getCompletableFuture();
        }

    @Override
    @SuppressWarnings("unchecked")
    public CompletableFuture putAll(Map map)
        {
        CacheService service = m_cache.getCacheService();
        if (service instanceof PartitionedService)
            {
            Map   mapByOwner = new HashMap<>();
            PartitionedService svcPart    = (PartitionedService) service;

            for (Map.Entry entry : map.entrySet())
                {
                Object oKey   = entry.getKey();
                Member member = svcPart.getKeyOwner(oKey);

                // member could be null here, indicating that the owning partition is orphaned
                Map mapMember = mapByOwner.get(member);
                if (mapMember == null)
                    {
                    mapMember = new HashMap();
                    mapByOwner.put(member, mapMember);
                    }
                mapMember.put(oKey, entry.getValue());
                }

            CompletableFuture[] aFuture = new CompletableFuture[mapByOwner.size()];

            int i = 0;
            for (Map mapMember : mapByOwner.values())
                {
                aFuture[i++] = invokeAll(mapMember.keySet(), CacheProcessors.putAll(mapMember));
                }

            return CompletableFuture.allOf(aFuture);
            }
        else
            {
            return AsyncNamedCache.super.putAll(map);
            }
        }

    // ---- helper methods --------------------------------------------------

    /**
     * Create and/or configure SingleEntryAsynchronousProcessor that should be
     * executed.
     *
     * @param processor  the EntryProcessor to use
     *
     * @return a fully configured SingleEntryAsynchronousProcessor to execute
     */
    protected  SingleEntryAsynchronousProcessor instantiateSingleEntryAsyncProcessor(
            InvocableMap.EntryProcessor processor)
        {
        return processor instanceof SingleEntryAsynchronousProcessor
                ? (SingleEntryAsynchronousProcessor) processor
                : new SingleEntryAsynchronousProcessor<>(
                        processor, getOrderId());
        }

    /**
     * Create and/or configure AsynchronousProcessor that should be executed.
     *
     * @param processor  the EntryProcessor to use
     *
     * @return a fully configured AsynchronousProcessor to execute
     */
    protected  AsynchronousProcessor instantiateMultiEntryAsyncProcessor(
            InvocableMap.EntryProcessor processor)
        {
        return processor instanceof AsynchronousProcessor
                ? (AsynchronousProcessor) processor
                : new AsynchronousProcessor<>(
                        processor, getOrderId());
        }

    /**
     * Create and/or configure StreamingAsynchronousProcessor that should be
     * executed.
     *
     * @param processor  the EntryProcessor to use
     * @param callback   a user-defined callback that will be called for each
     *                   partial result
     *
     * @return a fully configured StreamingAsynchronousProcessor to execute
     */
    protected  StreamingAsynchronousProcessor instantiateStreamingAsyncProcessor(
            InvocableMap.EntryProcessor processor,
            Consumer> callback)
        {
        return processor instanceof StreamingAsynchronousProcessor
                ? (StreamingAsynchronousProcessor) processor
                : new StreamingAsynchronousProcessor<>(
                        processor, getOrderId(), callback);
        }

    /**
     * Create and/or configure AsynchronousAggregator that should be executed.
     *
     * @param aggregator  the EntryAggregator to use
     *
     * @return a fully configured AsynchronousProcessor to execute
     */
    @SuppressWarnings("unchecked")
    protected  AsynchronousAggregator instantiateAsyncAggregator(
            InvocableMap.EntryAggregator aggregator)
        {
        if (aggregator instanceof AsynchronousAggregator)
            {
            return (AsynchronousAggregator) aggregator;
            }
        if (aggregator instanceof StreamingAggregator)
            {
            return new AsynchronousAggregator<>((StreamingAggregator) aggregator, getOrderId());
            }
        throw new IllegalArgumentException("Aggregator must be a StreamingAggregator or AsynchronousAggregator");
        }

    /**
     * Return unit-of-order id.
     *
     * @return unit-of-order id
     */
    protected int getOrderId()
        {
        return m_options.get(OrderBy.class).getOrderId();
        }

    // ---- data members ----------------------------------------------------

    /**
     * The wrapped NamedCache instance to delegate invocations to.
     */
    protected final NamedCache m_cache;

    /**
     * The configuration options.
     */
    protected final Options m_options;
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy