Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.turbospaces.ebean.JGroupsBroadcastChannel Maven / Gradle / Ivy
package com.turbospaces.ebean;
import java.io.Serializable;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
import org.apache.commons.lang3.time.StopWatch;
import org.jgroups.blocks.MethodCall;
import org.jgroups.blocks.RequestOptions;
import org.jgroups.blocks.RpcDispatcher;
import org.jgroups.util.RspList;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.MoreExecutors;
import com.turbospaces.cfg.ApplicationProperties;
import com.turbospaces.common.PlatformUtil;
import com.turbospaces.executor.DefaultPlatformExecutorService;
import io.ebean.cache.ServerCacheNotification;
import io.ebean.cache.ServerCacheType;
import io.ebeaninternal.server.cache.CachedBeanData;
import io.ebeaninternal.server.cache.CachedManyIds;
import io.micrometer.core.instrument.MeterRegistry;
import io.vavr.CheckedFunction0;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@SuppressWarnings("serial")
public class JGroupsBroadcastChannel implements BroadcastChannel, InitializingBean, DisposableBean {
private final RpcDispatcher dispatcher;
private final DefaultPlatformExecutorService platform;
public JGroupsBroadcastChannel(ApplicationProperties props, MeterRegistry meterRegistry, RpcDispatcher dispatcher) {
this.dispatcher = Objects.requireNonNull(dispatcher);
platform = new DefaultPlatformExecutorService(props, meterRegistry, props.APP_PLATFORM_POOL_SIZE.get());
platform.setBeanName("jgroups-rpc-dispatcher");
}
@Override
public void afterPropertiesSet() throws Exception {
platform.afterPropertiesSet();
}
@Override
public void destroy() throws Exception {
platform.destroy();
}
@Override
public FluentFuture>> broadcastPutAsync(String cacheKey, ServerCacheType type, String key, Object obj) {
//
// ~ fast and reusable output stream
//
UnsynchronizedByteArrayOutputStream out = UnsynchronizedByteArrayOutputStream.builder().get();
//
// ~ based on cache type
//
byte[] kser = PlatformUtil.serialize(out, key);
byte[] vser = switch (type) {
case NATURAL_KEY -> PlatformUtil.serialize(out, Serializable.class.cast(obj));
case BEAN -> PlatformUtil.serialize(out, CachedBeanData.class.cast(obj));
case COLLECTION_IDS -> PlatformUtil.serialize(out, CachedManyIds.class.cast(obj));
default -> throw new IllegalArgumentException("Unexpected cache type: " + type);
};
//
// ~ GC as fast as possible
//
out.reset();
StopWatch stopWatch = StopWatch.createStarted();
FluentFuture>> fluent = FluentFuture.from(platform.submit(new CheckedFunction0<>() {
@Override
public CompletableFuture> apply() throws Throwable {
CompletableFuture> future = CompletableFuture.completedFuture(null);
if (dispatcher.getChannel().isOpen()) {
MethodCall call = new MethodCall(JGroupsCacheManager.METHOD_ON_CACHE_PUT, cacheKey, kser, vser);
future = dispatcher.callRemoteMethodsWithFuture(null, call, RequestOptions.ASYNC());
stopWatch.stop();
}
return future;
}
}));
fluent.addCallback(new FutureCallback() {
@Override
public void onSuccess(Object result) {
log.trace("putted {} entry on remote nodes by key: {} value: {} in: {}", cacheKey, key, obj, stopWatch);
long time = stopWatch.getTime(TimeUnit.SECONDS);
if (time > 0) {
log.error("put operation took too long: {}", stopWatch);
}
}
@Override
public void onFailure(Throwable t) {
log.error(t.getMessage(), t);
}
}, MoreExecutors.directExecutor());
return fluent;
}
@Override
public FluentFuture>> broadcastRemoveAsync(String cacheKey, String key) {
//
// ~ fast and reusable output stream
//
UnsynchronizedByteArrayOutputStream out = UnsynchronizedByteArrayOutputStream.builder().get();
byte[] kser = PlatformUtil.serialize(out, key);
//
// ~ GC as fast as possible
//
out.reset();
StopWatch stopWatch = StopWatch.createStarted();
FluentFuture>> fluent = FluentFuture.from(platform.submit(new CheckedFunction0<>() {
@Override
public CompletableFuture> apply() throws Throwable {
CompletableFuture> future = CompletableFuture.completedFuture(null);
if (dispatcher.getChannel().isOpen()) {
MethodCall call = new MethodCall(JGroupsCacheManager.METHOD_ON_CHANGE_REMOVE, cacheKey, kser);
future = dispatcher.callRemoteMethodsWithFuture(null, call, RequestOptions.ASYNC());
stopWatch.stop();
}
return future;
}
}));
fluent.addCallback(new FutureCallback() {
@Override
public void onSuccess(Object result) {
log.trace("removed {} entry on remote nodes by key: {} in: {}", cacheKey, key, stopWatch);
long time = stopWatch.getTime(TimeUnit.SECONDS);
if (time > 0) {
log.error("remove operation took too long: {}", stopWatch);
}
}
@Override
public void onFailure(Throwable t) {
log.error(t.getMessage(), t);
}
}, MoreExecutors.directExecutor());
return fluent;
}
@Override
public FluentFuture>> broadcastClearAllAsync(String cacheKey) {
StopWatch stopWatch = StopWatch.createStarted();
FluentFuture>> fluent = FluentFuture.from(platform.submit(new CheckedFunction0<>() {
@Override
public CompletableFuture> apply() throws Throwable {
CompletableFuture> future = CompletableFuture.completedFuture(null);
if (dispatcher.getChannel().isOpen()) {
MethodCall call = new MethodCall(JGroupsCacheManager.METHOD_ON_CACHE_CLEAR, cacheKey);
future = dispatcher.callRemoteMethodsWithFuture(null, call, RequestOptions.ASYNC());
stopWatch.stop();
}
return future;
}
}));
fluent.addCallback(new FutureCallback() {
@Override
public void onSuccess(Object result) {
log.info("cleared {} on remote nodes in: {}", cacheKey, stopWatch);
long time = stopWatch.getTime(TimeUnit.SECONDS);
if (time > 0) {
log.error("clear operation took too long: {}", stopWatch);
}
}
@Override
public void onFailure(Throwable t) {
log.error(t.getMessage(), t);
}
}, MoreExecutors.directExecutor());
return fluent;
}
@Override
public FluentFuture>> broadcastClearAllAsync() {
StopWatch stopWatch = StopWatch.createStarted();
FluentFuture>> fluent = FluentFuture.from(platform.submit(new CheckedFunction0<>() {
@Override
public CompletableFuture> apply() throws Throwable {
CompletableFuture> future = CompletableFuture.completedFuture(null);
if (dispatcher.getChannel().isOpen()) {
MethodCall call = new MethodCall(JGroupsCacheManager.METHOD_ON_CACHE_CLEAR_ALL, true);
future = dispatcher.callRemoteMethodsWithFuture(null, call, RequestOptions.ASYNC());
stopWatch.stop();
}
return future;
}
}));
fluent.addCallback(new FutureCallback() {
@Override
public void onSuccess(Object result) {
long time = stopWatch.getTime(TimeUnit.SECONDS);
if (time > 0) {
log.error("clearAll operation took too long: {}", stopWatch);
}
}
@Override
public void onFailure(Throwable t) {
log.error(t.getMessage(), t);
}
}, MoreExecutors.directExecutor());
return fluent;
}
@Override
public FluentFuture>> broadcastAsync(ServerCacheNotification notification, String data) {
StopWatch stopWatch = StopWatch.createStarted();
FluentFuture>> fluent = FluentFuture.from(platform.submit(new CheckedFunction0<>() {
@Override
public CompletableFuture> apply() throws Throwable {
CompletableFuture> future = CompletableFuture.completedFuture(null);
if (dispatcher.getChannel().isOpen()) {
MethodCall call = new MethodCall(JGroupsCacheManager.METHOD_ON_MODIFIED, data);
future = dispatcher.callRemoteMethodsWithFuture(null, call, RequestOptions.ASYNC());
stopWatch.stop();
}
return future;
}
}));
fluent.addCallback(new FutureCallback() {
@Override
public void onSuccess(Object result) {
long time = stopWatch.getTime(TimeUnit.SECONDS);
if (time > 0) {
log.error("notify operation took too long: {} for tables: {}", stopWatch, notification.getDependentTables());
}
}
@Override
public void onFailure(Throwable t) {
log.error(t.getMessage(), t);
}
}, MoreExecutors.directExecutor());
return fluent;
}
}