[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