/* * Copyright (c) 2015 The original author or authors * --------------------------------- * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Apache License v2.0 is available at * http://www.opensource.org/licenses/apache2.0.php * * You may elect to redistribute this code under either of these licenses. */ package io.vertx.spi.cluster.ignite.impl; import io.vertx.core.Future; import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.VertxException; import io.vertx.core.impl.ContextInternal; import io.vertx.core.impl.VertxInternal; import io.vertx.core.shareddata.AsyncMap; import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteException; import org.apache.ignite.cache.query.ScanQuery; import org.apache.ignite.lang.IgniteFuture; import javax.cache.Cache; import javax.cache.expiry.CreatedExpiryPolicy; import javax.cache.expiry.Duration; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Function; import static io.vertx.spi.cluster.ignite.impl.ClusterSerializationUtils.marshal; import static io.vertx.spi.cluster.ignite.impl.ClusterSerializationUtils.unmarshal; /** * Async wrapper for {@link MapImpl}. * * @author Andrey Gura */ public class AsyncMapImpl<K, V> implements AsyncMap<K, V> { private final VertxInternal vertx; private final IgniteCache<K, V> cache; /** * Constructor. * * @param cache {@link IgniteCache} instance. * @param vertx {@link Vertx} instance. */ public AsyncMapImpl(IgniteCache<K, V> cache, VertxInternal vertx) { this.cache = cache; this.vertx = vertx; } @Override public Future<V> get(K k) { return execute(cache -> cache.getAsync(marshal(k))); } @Override public Future<Void> put(K k, V v) { return execute(cache -> cache.putAsync(marshal(k), marshal(v))); } @Override public Future<Void> put(K k, V v, long ttl) { return executeWithTtl(cache -> cache.putAsync(marshal(k), marshal(v)), ttl); } @Override public Future<V> putIfAbsent(K k, V v) { return execute(cache -> cache.getAndPutIfAbsentAsync(marshal(k), marshal(v))); } @Override public Future<V> putIfAbsent(K k, V v, long ttl) { return executeWithTtl(cache -> cache.getAndPutIfAbsentAsync(marshal(k), marshal(v)), ttl); } @Override public Future<V> remove(K k) { return execute(cache -> cache.getAndRemoveAsync(marshal(k))); } @Override public Future<Boolean> removeIfPresent(K k, V v) { return execute(cache -> cache.removeAsync(marshal(k), marshal(v))); } @Override public Future<V> replace(K k, V v) { return execute(cache -> cache.getAndReplaceAsync(marshal(k), marshal(v))); } @Override public Future<Boolean> replaceIfPresent(K k, V oldValue, V newValue) { return execute(cache -> cache.replaceAsync(marshal(k), marshal(oldValue), marshal(newValue))); } @Override public Future<Void> clear() { return execute(IgniteCache::clearAsync); } @Override public Future<Integer> size() { return execute(IgniteCache::sizeAsync); } @Override public Future<Set<K>> keys() { return entries().map(Map::keySet); } @Override public Future<List<V>> values() { return entries().map(map -> new ArrayList<>(map.values())); } @Override public Future<Map<K, V>> entries() { return vertx.executeBlocking(fut -> { List<Cache.Entry<K, V>> all = cache.query(new ScanQuery<K, V>()).getAll(); Map<K, V> map = new HashMap<>(all.size()); for (Cache.Entry<K, V> entry : all) { map.put(unmarshal(entry.getKey()), unmarshal(entry.getValue())); } fut.complete(map); }); } private <T> Future<T> execute(Function<IgniteCache<K, V>, IgniteFuture<T>> cacheOp) { return executeWithTtl(cacheOp, -1); } /** * @param ttl Time to live in ms. */ private <T> Future<T> executeWithTtl(Function<IgniteCache<K, V>, IgniteFuture<T>> cacheOp, long ttl) { ContextInternal ctx = vertx.getOrCreateContext(); Promise<T> promise = ctx.promise(); IgniteCache<K, V> cache0 = ttl > 0 ? cache.withExpiryPolicy(new CreatedExpiryPolicy(new Duration(TimeUnit.MILLISECONDS, ttl))) : cache; IgniteFuture<T> future = cacheOp.apply(cache0); future.listen(fut -> { try { promise.complete(unmarshal(future.get())); } catch (IgniteException e) { promise.fail(new VertxException(e)); } }); return promise.future(); } }