[infinispan-commits] Infinispan SVN: r1627 - trunk/core/src/main/java/org/infinispan/io.
infinispan-commits at lists.jboss.org
infinispan-commits at lists.jboss.org
Fri Mar 26 11:00:31 EDT 2010
Author: manik.surtani at jboss.com
Date: 2010-03-26 11:00:30 -0400 (Fri, 26 Mar 2010)
New Revision: 1627
Added:
trunk/core/src/main/java/org/infinispan/io/GridFile.java
trunk/core/src/main/java/org/infinispan/io/GridFilesystem.java
trunk/core/src/main/java/org/infinispan/io/GridInputStream.java
trunk/core/src/main/java/org/infinispan/io/GridOutputStream.java
Log:
[ISPN-382] (Port grid file system from JGroups to Infinispan)
Added: trunk/core/src/main/java/org/infinispan/io/GridFile.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/io/GridFile.java (rev 0)
+++ trunk/core/src/main/java/org/infinispan/io/GridFile.java 2010-03-26 15:00:30 UTC (rev 1627)
@@ -0,0 +1,413 @@
+package org.infinispan.io;
+
+import org.infinispan.AdvancedCache;
+import org.infinispan.Cache;
+import org.infinispan.context.Flag;
+import org.jgroups.util.Streamable;
+import org.jgroups.util.Util;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Set;
+
+import static org.infinispan.context.Flag.FORCE_SYNCHRONOUS;
+
+/**
+ * Subclass of File to iterate through directories and files in a grid
+ *
+ * @author Bela Ban
+ */
+public class GridFile extends File {
+ private static final long serialVersionUID = -6729548421029004260L;
+ private final AdvancedCache<String, Metadata> metadataCache;
+ private final GridFilesystem fs;
+ private final String name;
+ private int chunk_size;
+
+ GridFile(String pathname, Cache<String, Metadata> metadataCache, int chunk_size, GridFilesystem fs) {
+ super(pathname);
+ this.fs = fs;
+ this.name = trim(pathname);
+ this.metadataCache = metadataCache.getAdvancedCache();
+ this.chunk_size = chunk_size;
+ initMetadata();
+ }
+
+ GridFile(String parent, String child, Cache<String, Metadata> metadataCache, int chunk_size, GridFilesystem fs) {
+ super(parent, child);
+ this.fs = fs;
+ this.name = trim(parent + File.separator + child);
+ this.metadataCache = metadataCache.getAdvancedCache();
+ this.chunk_size = chunk_size;
+ initMetadata();
+ }
+
+ GridFile(File parent, String child, Cache<String, Metadata> metadataCache, int chunk_size, GridFilesystem fs) {
+ super(parent, child);
+ this.fs = fs;
+ this.name = trim(parent.getAbsolutePath() + File.separator + child);
+ this.metadataCache = metadataCache.getAdvancedCache();
+ this.chunk_size = chunk_size;
+ initMetadata();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getPath() {
+ String my_path = super.getPath();
+ if (my_path != null && my_path.endsWith(File.separator)) {
+ int index = my_path.lastIndexOf(File.separator);
+ if (index != -1)
+ my_path = my_path.substring(0, index);
+ }
+ return my_path;
+ }
+
+ @Override
+ public long length() {
+ Metadata metadata = metadataCache.get(getPath());
+ if (metadata != null)
+ return metadata.length;
+ return 0;
+ }
+
+ void setLength(int new_length) {
+ Metadata metadata = metadataCache.get(getPath());
+ if (metadata != null) {
+ metadata.length = new_length;
+ metadata.setModificationTime(System.currentTimeMillis());
+ metadataCache.put(getPath(), metadata);
+ } else
+ System.err.println("metadata for " + getPath() + " not found !");
+ }
+
+ public int getChunkSize() {
+ return chunk_size;
+ }
+
+ @Override
+ public boolean createNewFile() throws IOException {
+ if (exists())
+ return true;
+ if (!checkParentDirs(getPath(), false))
+ return false;
+ metadataCache.withFlags(FORCE_SYNCHRONOUS).put(getPath(), new Metadata(0, System.currentTimeMillis(), chunk_size, Metadata.FILE));
+ return true;
+ }
+
+ @Override
+ public boolean delete() {
+ return delete(false); // asynchronous delete by default
+ }
+
+ public boolean delete(boolean synchronous) {
+ if (!exists())
+ return false;
+ if (isFile()) {
+ fs.remove(getPath(), synchronous); // removes all the chunks belonging to the file
+ if (synchronous)
+ metadataCache.withFlags(FORCE_SYNCHRONOUS).remove(getPath()); // removes the metadata information
+ else
+ metadataCache.remove(getPath()); // removes the metadata information
+ return true;
+ }
+ if (isDirectory()) {
+ File[] files = listFiles();
+ if (files != null && files.length > 0)
+ return false;
+ fs.remove(getPath(), synchronous); // removes all the chunks belonging to the file
+ if (synchronous)
+ metadataCache.withFlags(FORCE_SYNCHRONOUS).remove(getPath()); // removes the metadata information
+ else
+ metadataCache.remove(getPath()); // removes the metadata information
+ }
+ return true;
+ }
+
+ @Override
+ public boolean mkdir() {
+ try {
+ boolean parents_exist = checkParentDirs(getPath(), false);
+ if (!parents_exist)
+ return false;
+ metadataCache.withFlags(FORCE_SYNCHRONOUS).put(getPath(), new Metadata(0, System.currentTimeMillis(), chunk_size, Metadata.DIR));
+ return true;
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ @Override
+ public boolean mkdirs() {
+ try {
+ boolean parents_exist = checkParentDirs(getPath(), true);
+ if (!parents_exist)
+ return false;
+ metadataCache.withFlags(FORCE_SYNCHRONOUS).put(getPath(), new Metadata(0, System.currentTimeMillis(), chunk_size, Metadata.DIR));
+ return true;
+ }
+ catch (IOException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean exists() {
+ return metadataCache.get(getPath()) != null;
+ }
+
+ @Override
+ public String[] list() {
+ return list(null);
+ }
+
+ @Override
+ public String[] list(FilenameFilter filter) {
+ return _list(filter);
+ }
+
+ @Override
+ public File[] listFiles() {
+ return listFiles((FilenameFilter) null);
+ }
+
+ @Override
+ public File[] listFiles(FilenameFilter filter) {
+ return _listFiles(filter);
+ }
+
+ @Override
+ public File[] listFiles(FileFilter filter) {
+ return _listFiles(filter);
+ }
+
+ @Override
+ public boolean isDirectory() {
+ Metadata val = metadataCache.get(getPath());
+ return val.isDirectory();
+ }
+
+ @Override
+ public boolean isFile() {
+ Metadata val = metadataCache.get(getPath());
+ return val.isFile();
+ }
+
+ protected void initMetadata() {
+ Metadata metadata = metadataCache.get(getPath());
+ if (metadata != null)
+ this.chunk_size = metadata.getChunkSize();
+ }
+
+ protected File[] _listFiles(Object filter) {
+ String[] files = _list(filter);
+ File[] retval = new File[files.length];
+ for (int i = 0; i < files.length; i++)
+ retval[i] = new GridFile(files[i], metadataCache, chunk_size, fs);
+ return retval;
+ }
+
+
+ protected String[] _list(Object filter) {
+ Set<String> keys = metadataCache.keySet();
+ if (keys == null)
+ return null;
+ Collection<String> list = new ArrayList<String>(keys.size());
+ for (String str : keys) {
+ if (isChildOf(getPath(), str)) {
+ if (filter instanceof FilenameFilter && !((FilenameFilter) filter).accept(new File(name), filename(str)))
+ continue;
+ else if (filter instanceof FileFilter && !((FileFilter) filter).accept(new File(str)))
+ continue;
+ list.add(str);
+ }
+ }
+ String[] retval = new String[list.size()];
+ int index = 0;
+ for (String tmp : list)
+ retval[index++] = tmp;
+ return retval;
+ }
+
+ /**
+ * Verifies whether child is a child (dir or file) of parent
+ *
+ * @param parent
+ * @param child
+ * @return True if child is a child, false otherwise
+ */
+ protected static boolean isChildOf(String parent, String child) {
+ if (parent == null || child == null)
+ return false;
+ if (!child.startsWith(parent))
+ return false;
+ if (child.length() <= parent.length())
+ return false;
+ int from = parent.equals(File.separator) ? parent.length() : parent.length() + 1;
+ // if(from-1 > child.length())
+ // return false;
+ String[] comps = Util.components(child.substring(from), File.separator);
+ return comps != null && comps.length <= 1;
+ }
+
+ protected static String filename(String full_path) {
+ String[] comps = Util.components(full_path, File.separator);
+ return comps != null ? comps[comps.length - 1] : null;
+ }
+
+
+ /**
+ * Checks whether the parent directories are present (and are directories). If create_if_absent is true,
+ * creates missing dirs
+ *
+ * @param path
+ * @param create_if_absent
+ * @return
+ */
+ protected boolean checkParentDirs(String path, boolean create_if_absent) throws IOException {
+ String[] components = Util.components(path, File.separator);
+ if (components == null)
+ return false;
+ if (components.length == 1) // no parent directories to create, e.g. "data.txt"
+ return true;
+
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+
+ for (int i = 0; i < components.length - 1; i++) {
+ String tmp = components[i];
+ if (!tmp.equals(File.separator)) {
+ if (first)
+ first = false;
+ else
+ sb.append(File.separator);
+ }
+ sb.append(tmp);
+ String comp = sb.toString();
+ if (exists(comp)) {
+ if (isFile(comp))
+ throw new IOException("cannot create " + path + " as component " + comp + " is a file");
+ } else {
+ if (create_if_absent)
+ metadataCache.put(comp, new Metadata(0, System.currentTimeMillis(), chunk_size, Metadata.DIR));
+ else
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ protected static String trim(String str) {
+ if (str == null) return null;
+ str = str.trim();
+ if (str.equals(File.separator))
+ return str;
+ String[] comps = Util.components(str, File.separator);
+ return comps != null && comps.length > 0 ? comps[comps.length - 1] : null;
+ }
+
+ private boolean exists(String key) {
+ return metadataCache.get(key) != null;
+ }
+
+ private boolean isFile(String key) {
+ Metadata val = metadataCache.get(key);
+ return val.isFile();
+ }
+
+
+ public static class Metadata implements Streamable {
+ public static final byte FILE = 1 << 0;
+ public static final byte DIR = 1 << 1;
+
+ private int length = 0;
+ private long modification_time = 0;
+ private int chunk_size = 0;
+ private byte flags = 0;
+
+
+ public Metadata() {
+ }
+
+ public Metadata(int length, long modification_time, int chunk_size, byte flags) {
+ this.length = length;
+ this.modification_time = modification_time;
+ this.chunk_size = chunk_size;
+ this.flags = flags;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public void setLength(int length) {
+ this.length = length;
+ }
+
+ public long getModificationTime() {
+ return modification_time;
+ }
+
+ public void setModificationTime(long modification_time) {
+ this.modification_time = modification_time;
+ }
+
+ public int getChunkSize() {
+ return chunk_size;
+ }
+
+ public boolean isFile() {
+ return Util.isFlagSet(flags, FILE);
+ }
+
+ public boolean isDirectory() {
+ return Util.isFlagSet(flags, DIR);
+ }
+
+ public String toString() {
+ boolean is_file = Util.isFlagSet(flags, FILE);
+ StringBuilder sb = new StringBuilder();
+ sb.append(getType());
+ if (is_file)
+ sb.append(", len=" + Util.printBytes(length) + ", chunk_size=" + chunk_size);
+ sb.append(", mod_time=" + new Date(modification_time));
+ return sb.toString();
+ }
+
+ public void writeTo(DataOutputStream out) throws IOException {
+ out.writeInt(length);
+ out.writeLong(modification_time);
+ out.writeInt(chunk_size);
+ out.writeByte(flags);
+ }
+
+ public void readFrom(DataInputStream in) throws IOException, IllegalAccessException, InstantiationException {
+ length = in.readInt();
+ modification_time = in.readLong();
+ chunk_size = in.readInt();
+ flags = in.readByte();
+ }
+
+ private String getType() {
+ if (Util.isFlagSet(flags, FILE))
+ return "file";
+ if (Util.isFlagSet(flags, DIR))
+ return "dir";
+ return "n/a";
+ }
+ }
+}
Property changes on: trunk/core/src/main/java/org/infinispan/io/GridFile.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/core/src/main/java/org/infinispan/io/GridFilesystem.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/io/GridFilesystem.java (rev 0)
+++ trunk/core/src/main/java/org/infinispan/io/GridFilesystem.java 2010-03-26 15:00:30 UTC (rev 1627)
@@ -0,0 +1,108 @@
+package org.infinispan.io;
+
+import org.infinispan.Cache;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Entry point for GridFile and GridInputStream / GridOutputStream
+ *
+ * @author Bela Ban
+ */
+public class GridFilesystem {
+ protected final Cache<String, byte[]> data;
+ protected final Cache<String, GridFile.Metadata> metadata;
+ protected final int default_chunk_size;
+
+ /**
+ * Creates an instance. The data and metadata caches should already have been setup and started
+ *
+ * @param data
+ * @param metadata
+ * @param default_chunk_size
+ */
+ public GridFilesystem(Cache<String, byte[]> data, Cache<String, GridFile.Metadata> metadata,
+ int default_chunk_size) {
+ this.data = data;
+ this.metadata = metadata;
+ this.default_chunk_size = default_chunk_size;
+ }
+
+ public GridFilesystem(Cache<String, byte[]> data, Cache<String, GridFile.Metadata> metadata) {
+ this(data, metadata, 8000);
+ }
+
+ public File getFile(String pathname) {
+ return getFile(pathname, default_chunk_size);
+ }
+
+ public File getFile(String pathname, int chunk_size) {
+ return new GridFile(pathname, metadata, chunk_size, this);
+ }
+
+ public File getFile(String parent, String child) {
+ return getFile(parent, child, default_chunk_size);
+ }
+
+ public File getFile(String parent, String child, int chunk_size) {
+ return new GridFile(parent, child, metadata, chunk_size, this);
+ }
+
+ public File getFile(File parent, String child) {
+ return getFile(parent, child, default_chunk_size);
+ }
+
+ public File getFile(File parent, String child, int chunk_size) {
+ return new GridFile(parent, child, metadata, chunk_size, this);
+ }
+
+ public OutputStream getOutput(String pathname) throws IOException {
+ return getOutput(pathname, false, default_chunk_size);
+ }
+
+ public OutputStream getOutput(String pathname, boolean append) throws IOException {
+ return getOutput(pathname, append, default_chunk_size);
+ }
+
+ public OutputStream getOutput(String pathname, boolean append, int chunk_size) throws IOException {
+ GridFile file = (GridFile) getFile(pathname, chunk_size);
+ if (!file.createNewFile())
+ throw new IOException("creation of " + pathname + " failed");
+
+ return new GridOutputStream(file, append, data, chunk_size);
+ }
+
+ public OutputStream getOutput(GridFile file) throws IOException {
+ if (!file.createNewFile())
+ throw new IOException("creation of " + file + " failed");
+ return new GridOutputStream(file, false, data, default_chunk_size);
+ }
+
+
+ public InputStream getInput(String pathname) throws FileNotFoundException {
+ GridFile file = (GridFile) getFile(pathname);
+ if (!file.exists())
+ throw new FileNotFoundException(pathname);
+ return new GridInputStream(file, data, default_chunk_size);
+ }
+
+ public InputStream getInput(File pathname) throws FileNotFoundException {
+ return pathname != null ? getInput(pathname.getPath()) : null;
+ }
+
+
+ public void remove(String path, boolean synchronous) {
+ if (path == null)
+ return;
+ GridFile.Metadata md = metadata.get(path);
+ if (md == null)
+ return;
+ int num_chunks = md.getLength() / md.getChunkSize() + 1;
+ for (int i = 0; i < num_chunks; i++)
+ data.remove(path + ".#" + i, synchronous);
+ }
+}
Property changes on: trunk/core/src/main/java/org/infinispan/io/GridFilesystem.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/core/src/main/java/org/infinispan/io/GridInputStream.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/io/GridInputStream.java (rev 0)
+++ trunk/core/src/main/java/org/infinispan/io/GridInputStream.java 2010-03-26 15:00:30 UTC (rev 1627)
@@ -0,0 +1,117 @@
+package org.infinispan.io;
+
+import org.infinispan.Cache;
+import org.jgroups.logging.Log;
+import org.jgroups.logging.LogFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author Bela Ban
+ */
+public class GridInputStream extends InputStream {
+ final Cache<String, byte[]> cache;
+ final int chunk_size;
+ final String name;
+ protected final GridFile file; // file representing this input stream
+ int index = 0; // index into the file for writing
+ int local_index = 0;
+ byte[] current_buffer = null;
+ boolean end_reached = false;
+ final static Log log = LogFactory.getLog(GridInputStream.class);
+
+ GridInputStream(GridFile file, Cache<String, byte[]> cache, int chunk_size) throws FileNotFoundException {
+ this.file = file;
+ this.name = file.getPath();
+ this.cache = cache;
+ this.chunk_size = chunk_size;
+ }
+
+ public int read() throws IOException {
+ int bytes_remaining_to_read = getBytesRemainingInChunk();
+ if (bytes_remaining_to_read == 0) {
+ if (end_reached)
+ return -1;
+ current_buffer = fetchNextChunk();
+ local_index = 0;
+ if (current_buffer == null)
+ return -1;
+ else if (current_buffer.length < chunk_size)
+ end_reached = true;
+ bytes_remaining_to_read = getBytesRemainingInChunk();
+ }
+ int retval = current_buffer[local_index++];
+ index++;
+ return retval;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int bytes_read = 0;
+ while (len > 0) {
+ int bytes_remaining_to_read = getBytesRemainingInChunk();
+ if (bytes_remaining_to_read == 0) {
+ if (end_reached)
+ return bytes_read > 0 ? bytes_read : -1;
+ current_buffer = fetchNextChunk();
+ local_index = 0;
+ if (current_buffer == null)
+ return bytes_read > 0 ? bytes_read : -1;
+ else if (current_buffer.length < chunk_size)
+ end_reached = true;
+ bytes_remaining_to_read = getBytesRemainingInChunk();
+ }
+ int bytes_to_read = Math.min(len, bytes_remaining_to_read);
+ // bytes_to_read=Math.min(bytes_to_read, current_buffer.length - local_index);
+ System.arraycopy(current_buffer, local_index, b, off, bytes_to_read);
+ local_index += bytes_to_read;
+ off += bytes_to_read;
+ len -= bytes_to_read;
+ bytes_read += bytes_to_read;
+ index += bytes_to_read;
+ }
+
+ return bytes_read;
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int available() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void close() throws IOException {
+ local_index = index = 0;
+ end_reached = false;
+ }
+
+ private int getBytesRemainingInChunk() {
+ // return chunk_size - local_index;
+ return current_buffer == null ? 0 : current_buffer.length - local_index;
+ }
+
+ private byte[] fetchNextChunk() {
+ int chunk_number = getChunkNumber();
+ String key = name + ".#" + chunk_number;
+ byte[] val = cache.get(key);
+ if (log.isTraceEnabled())
+ log.trace("fetching index=" + index + ", key=" + key + ": " + (val != null ? val.length + " bytes" : "null"));
+ return val;
+ }
+
+ private int getChunkNumber() {
+ return index / chunk_size;
+ }
+}
Property changes on: trunk/core/src/main/java/org/infinispan/io/GridInputStream.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/core/src/main/java/org/infinispan/io/GridOutputStream.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/io/GridOutputStream.java (rev 0)
+++ trunk/core/src/main/java/org/infinispan/io/GridOutputStream.java 2010-03-26 15:00:30 UTC (rev 1627)
@@ -0,0 +1,100 @@
+package org.infinispan.io;
+
+import org.infinispan.Cache;
+import org.jgroups.logging.Log;
+import org.jgroups.logging.LogFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * @author Bela Ban
+ */
+public class GridOutputStream extends OutputStream {
+
+ final Cache<String, byte[]> cache;
+ final int chunk_size;
+ final String name;
+ protected final GridFile file; // file representing this output stream
+ int index = 0; // index into the file for writing
+ int local_index = 0;
+ final byte[] current_buffer;
+ static final Log log = LogFactory.getLog(GridOutputStream.class);
+
+
+ GridOutputStream(GridFile file, boolean append, Cache<String, byte[]> cache, int chunk_size) throws FileNotFoundException {
+ this.file = file;
+ this.name = file.getPath();
+ this.cache = cache;
+ this.chunk_size = chunk_size;
+ current_buffer = new byte[chunk_size];
+ }
+
+ public void write(int b) throws IOException {
+ int remaining = getBytesRemainingInChunk();
+ if (remaining == 0) {
+ flush();
+ local_index = 0;
+ remaining = chunk_size;
+ }
+ current_buffer[local_index] = (byte) b;
+ local_index++;
+ index++;
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ if (b != null)
+ write(b, 0, b.length);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ while (len > 0) {
+ int remaining = getBytesRemainingInChunk();
+ if (remaining == 0) {
+ flush();
+ local_index = 0;
+ remaining = chunk_size;
+ }
+ int bytes_to_write = Math.min(remaining, len);
+ System.arraycopy(b, off, current_buffer, local_index, bytes_to_write);
+ off += bytes_to_write;
+ len -= bytes_to_write;
+ local_index += bytes_to_write;
+ index += bytes_to_write;
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ flush();
+ reset();
+ }
+
+ @Override
+ public void flush() throws IOException {
+ int chunk_number = getChunkNumber();
+ String key = name + ".#" + chunk_number;
+ byte[] val = new byte[local_index];
+ System.arraycopy(current_buffer, 0, val, 0, local_index);
+ cache.put(key, val);
+ if (log.isTraceEnabled())
+ log.trace("put(): index=" + index + ", key=" + key + ": " + val.length + " bytes");
+ file.setLength(index);
+ }
+
+ private int getBytesRemainingInChunk() {
+ return chunk_size - local_index;
+ }
+
+
+ private int getChunkNumber() {
+ return (index - 1) / chunk_size;
+ }
+
+ private void reset() {
+ index = local_index = 0;
+ }
+}
Property changes on: trunk/core/src/main/java/org/infinispan/io/GridOutputStream.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
More information about the infinispan-commits
mailing list