In Apache Geode, which is one of the distributed system type KVS implementations, it is common to use a function called Function Execution when you want to execute some logic on the server side. However, since Functoin Execution is highly functional, the amount of coding other than setting items and actual logic tends to be large, and specific logic is executed only once on one of the cache server nodes regardless of the data arrangement in the cluster and returned. It may be a little daunting to use it in simple cases where you don't even ask for a value.
In this article, I will show you how to execute logic on the server side more easily with Apache Geode without using the Function Execution function. Hereinafter, the entity that executes arbitrary logic will be referred to as a "command". The method in this article has been confirmed to work with Apache Geode 1.6.0.
In this article, as a simple server-side logic execution example, the following contents will be set and implemented without using the Function Execution function.
--Execute the command to delete all data in the specified region (that is, execute Regoin # clear) only once on any cache server node in the cluster, no return value
The logic is executed on the server side without using the Function Execution function by the following mechanism.
refid = REPLICATED_PROXY) put --key is not used, so any value CacheWriter that was previously assigned to the Command region on the server side.Here, the reason for using CacheWriter instead of the commonly used CacheListner is that the former basically allows all the assigned cache servers to react and the command to be executed twice. This is because the latter runs on one of the granted cache servers, whereas it is sexual.
For reference, the execution image diagram is posted below.

As a policy, assuming that a class is prepared individually for each command, the following command interface is defined in order to standardize the logic for executing commands with CacheWriter.
Command.java
public interface Command {
public void process();
}
Next, in the form of implementing this, write the data deletion command class of the specified region as follows. Execute Region # clear with the process method defined in the command interface based on the region ( regionName) specified when instantiating this command class.
ClearRegionCommand.java
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.Region;
import java.io.Serializable;
public class ClearRegionCommand implements Command, Serializable {
private String regionName;
public ClearRegionCommand(String regionName) {
this.regionName = regionName;
}
public void process() {
Region region = CacheFactory.getAnyInstance().getRegion(this.regionName);
if (region != null) {
region.clear();
}
}
}
Note that the command object itself is sent to the server over the network, so it must be implemented as a serializable object. Here, java.io.Serializable has been implemented, but since it is Apache Geode, PDX can be used as the object serialization technology.
And then there is the implementation of CacheWriter that executes the command. In the beforeCreate method, get the command object from the event generated by put and execute the process method. By the way, CacheWriter is often defined in the cache configuration file (hereinafter, cache.xml), and Declarable is implemented just in case.
ProcessCommandCacheWriter.java
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheWriterException;
import org.apache.geode.cache.Declarable;
import org.apache.geode.cache.EntryEvent;
import org.apache.geode.cache.util.CacheWriterAdapter;
import java.util.Properties;
public class ProcessCommandCacheWriter extends CacheWriterAdapter<Integer,Command> implements Declarable {
public void beforeCreate(EntryEvent<Integer,Command> event) throws CacheWriterException {
Command command = event.getNewValue();
command.process();
}
public void initialize(Cache cache, Properties properties) { }
public void close() {}
}
CacheWriter settingsHere, it is set using cache.xml. It will be assigned to the Command region where REPLICATE_PROXY is set in refid. The Example region will be the sample region to be executed by the command implemented this time, Regoin # clear.
cache.xml
<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://geode.apache.org/schema/cache"
xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd"
version="1.0" lock-lease="120" lock-timeout="60" search-timeout="300" is-server="false" copy-on-read="false">
<cache-server port="0" />
<region name="Example" refid="REPLICATE" />
<region name="Command" refid="REPLICATE_PROXY">
<region-attributes>
<cache-writer>
<class-name>ProcessCommandCacheWriter</class-name>
</cache-writer>
</region-attributes>
</region>
</cache>
Commands submitted by the client are executed on the server, so you need to set the server's CLASSPATH to the paths to various related classes. The command class body (here, ClearRegionCommand) can be dynamically set with the gfsh deploy command if necessary, but at least the path to the following classes must be set when starting the server. There is.
-- CacheWriter class (here, ProcessCommandCacheWriter class)
--Command interface (here, Command interface)
The interface doesn't seem to be able to set the CLASSPATH with the gfsh deploy command
Create a command object and code it in the Command region as put as a value, as shown below.
ClientCache cache = new ClientCacheFactory()
.set("cache-xml-file", "client-cache.xml")
.create();
cache.getRegion("Command").put(0, new ClearRegionCommand("Example"));
For reference, the following is a sample cache.xml on the client side.
client-cache.xml
<?xml version="1.0" encoding="UTF-8"?>
<client-cache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://geode.apache.org/schema/cache"
xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd"
version="1.0" copy-on-read="false">
<pool name="MyPool" subscription-enabled="true">
<locator host="xxx.xxx.xxx.xxx" port="xxxxx" />
</pool>
<region name="Example">
<region-attributes pool-name="MyPool" refid="CACHING_PROXY" />
</region>
<region name="Command">
<region-attributes pool-name="MyPool" refid="PROXY" />
</region>
</client-cache>
Summarizing it as an article, I feel that there are more codes and settings than I expected in the case of Function Executoin, but I think that it is easy for users to input commands from the client in one line. I am.
Furthermore, with the method introduced this time, by adding the Gateway Sender setting to the Command region, it is possible to perform the feat of executing arbitrary logic even in another cluster with the Gateway Receiver set via the WAN. If you are interested and in demand, give it a try.
Recommended Posts