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