/*
* JBoss, Home of Professional Open Source
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2005-2006,
* @author JBoss Inc.
*/
/*
* Copyright (C) 1998, 1999, 2000, 2001,
*
* Arjuna Solutions Limited,
* Newcastle upon Tyne,
* Tyne and Wear,
* UK.
*
* $Id: FileSystemStore.java 2342 2006-03-30 13:06:17Z $
*/
package com.arjuna.ats.internal.arjuna.objectstore;
import com.arjuna.ats.arjuna.ArjunaNames;
import com.arjuna.ats.arjuna.objectstore.*;
import com.arjuna.ats.arjuna.common.*;
import com.arjuna.ats.arjuna.logging.tsLogger;
import com.arjuna.ats.arjuna.logging.FacilityCode;
import com.arjuna.ats.arjuna.state.*;
import com.arjuna.ats.arjuna.gandiva.ClassName;
import com.arjuna.ats.arjuna.gandiva.ObjectName;
import com.arjuna.ats.arjuna.utils.FileLock;
import com.arjuna.ats.arjuna.utils.Utility;
import java.util.Hashtable;
import com.arjuna.ats.arjuna.exceptions.ObjectStoreException;
import java.lang.NumberFormatException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import com.arjuna.common.util.logging.*;
/**
* The basic class for file system object stores. This is not actually
* an object store implementation, since other classes must provide
* implementations of the abstract methods. It does provide implementations
* of common methods though.
*
* @author Mark Little (mark@arjuna.com)
* @version $Id: FileSystemStore.java 2342 2006-03-30 13:06:17Z $
* @since JTS 1.0.
*
*
* @message com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_1 [com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_1] - FileSystemStore::setupStore - cannot access root of object store: {0}
* @message com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_2 [com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_2] - FileSystemStore.removeFromCache - no entry for {0}
* @message com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_2a [com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_3] - FileSystemStore::allObjUids - could not pack Uid.
* @message com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_3 [com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_3] - FileSystemStore::allObjUids - could not pack end of list Uid.
* @message com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_4 [com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_4] - FileSytemStore::allTypes - could not pack entry string.
* @message com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_5 [com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_5] - FileSystemStore::allTypes - could not pack end of list string.
* @message com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_6 [com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_6] - FileSystemStore::setupStore - error from unpack object store.
* @message com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_7 [com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_7] - FileSystemStore::allTypes - could not pack entry string.
* @message com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_8 [com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_8] - FileSystemStore::createHierarchy - null directory name.
* @message com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_20 [com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_20] - FileSystemStore.renameFromTo - from {0} not present. Possibly renamed by crash recovery.
*/
public abstract class FileSystemStore extends ObjectStoreImple
{
public FileSystemStore (String locationOfStore, int ss)
{
super(ss);
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.CONSTRUCTORS, VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_OBJECT_STORE,
"FileSystemStore.FileSystemStore("+locationOfStore+")");
}
fullStoreName = null;
localStoreRoot = null;
isValid = true;
try
{
setupStore(locationOfStore);
}
catch (ObjectStoreException e)
{
isValid = false;
tsLogger.arjLogger.warn(e.getMessage());
throw new com.arjuna.ats.arjuna.exceptions.FatalError(e.toString());
}
}
/**
* This constructor assumes that everything for the objectstore
* is setup in the associated ObjectName. Sensible defaults are
* used otherwise.
*/
public FileSystemStore (ObjectName objName)
{
super(objName);
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.CONSTRUCTORS, VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_OBJECT_STORE, "FileSystemStore.FileSystemStore("+objName+")");
}
fullStoreName = null;
localStoreRoot = null;
isValid = true;
try
{
setupStore("");
}
catch (ObjectStoreException e)
{
isValid = false;
tsLogger.arjLogger.warn(e.getMessage());
throw new com.arjuna.ats.arjuna.exceptions.FatalError(e.toString());
}
}
public String getStoreName ()
{
return localStoreRoot;
}
/*
* read an uncommitted instance of State out of the object store.
* The instance is identified by the unique id and type
*/
public InputObjectState read_committed (Uid storeUid, String tName) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_OBJECT_STORE, "FileSystemStore.read_committed("+storeUid+", "+tName+")");
}
return read_state(storeUid, tName, ObjectStore.OS_ORIGINAL);
}
public InputObjectState read_uncommitted (Uid storeUid, String tName) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_OBJECT_STORE, "FileSystemStore.read_uncommitted("+storeUid+", "+tName+")");
}
return read_state(storeUid, tName, ObjectStore.OS_SHADOW);
}
public boolean remove_committed (Uid storeUid, String tName) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_OBJECT_STORE,
"FileSystemStore.remove_committed("+storeUid+", "+tName+")");
}
return remove_state(storeUid, tName, ObjectStore.OS_ORIGINAL);
}
public boolean remove_uncommitted (Uid storeUid, String tName) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_OBJECT_STORE,
"FileSystemStore.remove_uncommitted("+storeUid+", "+tName+")");
}
return remove_state(storeUid, tName, ObjectStore.OS_SHADOW);
}
public boolean write_committed (Uid storeUid, String tName, OutputObjectState state) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_OBJECT_STORE,
"FileSystemStore.write_committed("+storeUid+", "+tName+")");
}
return write_state(storeUid, tName, state, ObjectStore.OS_ORIGINAL);
}
public boolean write_uncommitted (Uid storeUid, String tName, OutputObjectState state) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_OBJECT_STORE,
"FileSystemStore.write_uncommitted("+storeUid+", "+tName+", "+state+")");
}
return write_state(storeUid, tName, state, ObjectStore.OS_SHADOW);
}
public final synchronized boolean storeValid ()
{
return isValid;
}
public final synchronized void makeInvalid ()
{
isValid = false;
}
public final synchronized void makeValid ()
{
isValid = true;
}
/**
* Given a type name initialise the <code>state</code> to contains all of
* the Uids of objects of that type
*/
public boolean allObjUids (String tName, InputObjectState state, int match) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_OBJECT_STORE,
"FileSystemStore.allObjUids("+tName+", "+state+", "+match+")");
}
String directory = null;
OutputObjectState store = new OutputObjectState();
/*
* If typename starts with a '/' then skip over it.
*/
if ((tName != null) && (tName.charAt(0) == File.separatorChar))
{
String s = tName.substring(1, tName.length());
directory = new String(fullStoreName + s);
}
else
directory = new String(fullStoreName + tName);
File f = new File(directory);
String[] entry = f.list();
if ((entry != null) && (entry.length > 0))
{
for (int i = 0; i < entry.length; i++)
{
try
{
Uid aUid = new Uid(entry[i], true);
if (!aUid.valid() || (aUid.equals(Uid.nullUid())))
{
String revealed = revealedId(entry[i]);
// don't want to give the same id twice.
if (present(revealed, entry))
aUid = null;
else
aUid = new Uid(revealed);
}
if ((aUid != null) && (aUid.valid()))
{
if ((aUid.notEquals(Uid.nullUid())) && ((match == ObjectStore.OS_UNKNOWN) ||
(isType(aUid, tName, match))))
{
if(scanZeroLengthFiles || new File(f, entry[i]).length() > 0) {
aUid.pack(store);
}
}
}
}
catch (NumberFormatException e)
{
/*
* Not a number at start of file.
*/
}
catch (IOException e)
{
throw new ObjectStoreException(tsLogger.log_mesg.getString("com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_2a"));
}
}
}
try
{
Uid.nullUid().pack(store);
}
catch (IOException e)
{
throw new ObjectStoreException(tsLogger.log_mesg.getString("com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_3"));
}
state.setBuffer(store.buffer());
store = null;
return true;
}
public boolean allTypes (InputObjectState foundTypes) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_OBJECT_STORE, "FileSystemStore.allTypes("+foundTypes+")");
}
boolean result = true;
String directory = new String(fullStoreName);
File f = new File(directory);
String[] entry = f.list();
if (entry == null)
return true;
OutputObjectState store = new OutputObjectState();
for (int i = 0; i < entry.length; i++)
{
if (!supressEntry(entry[i]))
{
File tmpFile = new File(directory+File.separator+entry[i]);
if (tmpFile.isDirectory())
{
try
{
store.packString(entry[i]);
result = allTypes(store, entry[i]);
}
catch (IOException e)
{
throw new ObjectStoreException(tsLogger.log_mesg.getString("com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_4"));
}
}
tmpFile = null;
}
}
try
{
store.packString("");
}
catch (IOException e)
{
throw new ObjectStoreException(tsLogger.log_mesg.getString("com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_5"));
}
foundTypes.setBuffer(store.buffer());
return result;
}
public synchronized void packInto (OutputBuffer buff) throws IOException
{
if (localStoreRoot != null)
{
if (localStoreRoot.compareTo("") == 0)
{
buff.packString(null);
return;
}
}
buff.packString(localStoreRoot);
}
public synchronized void unpackFrom (InputBuffer buff) throws IOException
{
try
{
setupStore(buff.unpackString());
}
catch (ObjectStoreException e)
{
throw new IOException(tsLogger.log_mesg.getString("com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_6"));
}
}
public ClassName className ()
{
return ArjunaNames.Implementation_ObjectStore_FileSystemStore();
}
public static ClassName name ()
{
return ArjunaNames.Implementation_ObjectStore_FileSystemStore();
}
protected abstract InputObjectState read_state (Uid u, String tn, int s) throws ObjectStoreException;
protected abstract boolean remove_state (Uid u, String tn, int s) throws ObjectStoreException;
protected abstract boolean write_state (Uid u, String tn, OutputObjectState buff, int s) throws ObjectStoreException;
/**
* Turn file sync on and off.
*/
protected synchronized final void syncOn ()
{
FileSystemStore.doSync = true;
}
protected synchronized final void syncOff ()
{
FileSystemStore.doSync = false;
}
/**
* Are synchronous write enabled?
*/
protected synchronized final boolean synchronousWrites ()
{
return FileSystemStore.doSync && syncWrites;
}
/**
* Lock the file in the object store.
*/
protected synchronized boolean lock (File fd, int lmode, boolean create)
{
FileLock fileLock = new FileLock(fd);
return fileLock.lock(lmode, create);
}
/**
* Unlock the file in the object store.
*/
protected synchronized boolean unlock (File fd)
{
FileLock fileLock = new FileLock(fd);
return fileLock.unlock();
}
/**
* Unlock and close the file. Note that if the unlock fails we set
* the return value to false to indicate an error but rely on the
* close to really do the unlock.
*/
protected boolean closeAndUnlock (File fd, FileInputStream ifile, FileOutputStream ofile)
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PRIVATE,
FacilityCode.FAC_OBJECT_STORE, "FileSystemStore.closeAndUnlock("+fd+", "+ifile+", "+ofile+")");
}
boolean closedOk = unlock(fd);
try
{
if (ifile != null)
ifile.close();
else
ofile.close();
}
catch (Exception e)
{
closedOk = false;
}
return closedOk;
}
protected File openAndLock (String fname, int lmode, boolean create) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PRIVATE,
FacilityCode.FAC_OBJECT_STORE, "FileSystemStore.openAndLock("+fname+", "+FileLock.modeString(lmode)+", "+create+")");
}
// File fd = (File) FdCache(fname);
File fd = null;
if (fd == null)
{
fd = new File(fname);
if (!fd.exists())
{
if (createHierarchy(fname))
{
if (!lock(fd, lmode, create))
{
return null;
}
else
return fd;
}
else
throw new ObjectStoreException("FileSystemStore.openAndLock failed to create hierarchy "+fname);
}
if (!lock(fd, lmode, create))
fd = null;
}
return fd;
}
/*
* Renaming on Unix works if the file to rename to already exists.
* However, on Windows if the file exists then rename fails! So, we
* need to delete the file to rename to before we can rename. But, we
* must ensure that we don't get into any race conditions, so we
* exclusively lock the file to be deleted first. Failure scenarios:
*
* (i) if we crash after deleting, but before we have had a chance to
* rename the file, then the lock file will exist and prevent anyone
* from deleting the shadow.
*
* (ii) if we crash after renaming and before the lock file is removed
* then subsequent lock attempts will fail, and the sys admin will
* have to resolve. But consistency will be maintained!
*
* When JDK 1.4 supports appears we will use the file-locking facility
* it provides.
*
* We have to use locks at deletion, but an implementation such as
* ShadowNoFileLockStore can still get away with no locking elsewhere
* to improve performance.
*/
protected synchronized final boolean renameFromTo (File from, File to)
{
if (!isWindows)
return from.renameTo(to);
else
{
// FileLock fl = new FileLock(to);
if (!from.exists())
{
/*
* from is in the cache, but not on disk. So, either
*
* (i) two different users are using the same state and
* should have been using the OS_SHARED flag.
*
* or
*
* (ii) crash recovery has recovered the state.
*
* If (ii) we can't force OS_SHARED on all users for the
* minority case. So, assume (ii) and issue a warning.
*/
removeFromCache(from.toString());
if (tsLogger.arjLoggerI18N.isWarnEnabled())
{
tsLogger.arjLoggerI18N.warn("com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_20",
new Object[]{from});
}
return true;
}
/*
* Let let crash recovery deal with this!
*/
// if (fl.lock(FileLock.F_WRLCK))
{
to.delete();
boolean res = from.renameTo(to);
// fl.unlock();
return true;
}
/*
else
{
if (tsLogger.arjLoggerI18N.isWarnEnabled())
{
tsLogger.arjLoggerI18N.warn("com.arjuna.ats.internal.arjuna.objectstore.ShadowingStore_21",
new Object[]{to});
}
return false;
}*/
}
}
protected FileSystemStore (int ss)
{
super(ss);
fullStoreName = null;
localStoreRoot = null;
isValid = true;
}
protected boolean allTypes (OutputObjectState foundTypes, String root) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PROTECTED,
FacilityCode.FAC_OBJECT_STORE,
"FileSystemStore.allTypes("+foundTypes+", "+root+")");
}
boolean result = true;
String directory = new String(fullStoreName + File.separator + root);
File f = new File(directory);
String[] entry = f.list();
if ((entry != null) && (entry.length > 0))
{
for (int i = 0; i < entry.length; i++)
{
if (!supressEntry(entry[i]))
{
try
{
File tmpFile = new File(directory+File.separator+entry[i]);
if (tmpFile.isDirectory())
{
String pack = truncate(entry[i]);
if ( pack.length() > 0 )
{
foundTypes.packString(root+File.separator+pack);
result = allTypes(foundTypes, root+File.separator+pack);
}
}
tmpFile = null;
}
catch (IOException e)
{
throw new ObjectStoreException(tsLogger.log_mesg.getString("com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_7"));
}
}
}
}
return result;
}
/**
* @return the file name for the state of the object
* identified by the Uid and TypeName. If the StateType argument
* is OS_SHADOW then the Uid part of the name includes # characters.
* The magic number SLOP below is the number of extra characters needed
* to make up the entire path.
*/
protected String genPathName (Uid objUid,
String tName, int ostype) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PROTECTED,
FacilityCode.FAC_OBJECT_STORE,
"FileSystemStore.genPathName("+objUid+", "+tName+", "+ostype+")");
}
String storeName = locateStore(getStoreName());
String cPtr = null;
String fname = null;
String os = objUid.fileStringForm(); // convert all ':' to '_' to be portable across file systems.
if ((tName == null) || (tName.length() == 0))
cPtr = "";
else
{
cPtr = tName;
/*
* Convert Unix separators to 'other', i.e., Windows!
*/
if (FileSystemStore.rewriteSeparator && (cPtr.indexOf(FileSystemStore.unixSeparator) != -1))
{
cPtr = cPtr.replace(FileSystemStore.unixSeparator, File.separatorChar);
}
}
/*
* storeName always ends in '/' so we can remove any
* at the start of the type name.
*/
if (cPtr.charAt(0) == File.separatorChar)
cPtr = cPtr.substring(1, cPtr.length());
if (cPtr.charAt(cPtr.length() -1) != File.separatorChar)
fname = storeName + cPtr + File.separator + os;
else
fname = storeName + cPtr + os;
/*
* Make sure we don't end in a '/'.
*/
if (fname.charAt(fname.length() -1) == File.separatorChar)
fname = fname.substring(0, fname.length() -2);
return fname;
}
protected synchronized boolean setupStore (String localOSRoot) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PROTECTED,
FacilityCode.FAC_OBJECT_STORE, "FileSystemStore.setupStore("+localOSRoot+")");
}
isValid = true;
if (localOSRoot == null)
localOSRoot = "";
localStoreRoot = localOSRoot;
fullStoreName = locateStore(localStoreRoot);
/* The root of the objectstore must exist and be writable */
if ((fullStoreName == null) || !createHierarchy(fullStoreName))
{
if (tsLogger.arjLoggerI18N.isWarnEnabled())
{
tsLogger.arjLoggerI18N.warn("com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_1",
new Object[]{fullStoreName});
}
isValid = false;
}
return isValid;
}
protected boolean supressEntry (String name)
{
if ((name.compareTo(".") == 0) || (name.compareTo("..") == 0))
return true;
else
return false;
}
protected String truncate (String value)
{
return value;
}
/**
* Attempt to build up the object store in the file system dynamically.
* This creates directories as required as new types are added to the
* store. Note that we made sure the root object store was created and
* writable at construction time.
*
* WARNING: on a multi-processor box it is possible that multiple threads may
* try to create the same hierarchy at the same time. What will tend to happen
* is that one thread will succeed and the other(s) will fail. However, if a failed
* thread just assumes that the directory is being created by another thread, then
* we're in trouble, because although this may be the case, the directory structure
* may not have actually been created - it may still be in the process of being
* created. So, we have to err on the side of caution and try to create the directory
* a few times. (This can happen across processes too.)
*/
protected synchronized final boolean createHierarchy (String path) throws ObjectStoreException
{
if (tsLogger.arjLogger.debugAllowed())
{
tsLogger.arjLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PROTECTED,
FacilityCode.FAC_OBJECT_STORE, "FileSystemStore.createHierarchy("+path+")");
}
if ((path != null) && (path.length() > 0))
{
File f = null;
/*
* Is string a complete directory list, or is it an
* absolute file name?
*/
if (path.charAt(path.length() -1) != File.separatorChar)
{
int index = path.lastIndexOf(File.separator);
if (index <= 0)
return true;
else
f = new File(path.substring(0, index));
}
else
f = new File(path);
int retryLimit = FileSystemStore.createRetry;
do
{
if (f.exists())
{
return true;
}
else
{
if (!f.mkdirs())
{
retryLimit--;
if (retryLimit == 0)
return false;
try
{
Thread.currentThread().sleep(FileSystemStore.createTimeout);
}
catch (Exception ex)
{
}
}
else
return true;
}
} while (!f.exists() && (retryLimit > 0));
return f.exists();
}
else
throw new ObjectStoreException(tsLogger.log_mesg.getString("com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_8"));
}
/**
* If this object store implementation is exclusively working on a set of
* object states, then this method will check a file cache first.
* Otherwise, we must go back to the file system each time to check the
* status of the file.
*
* If we add a FileDescriptor cache a la the C++ version then we would
* be able to get rid of the state cache and simply check to see if we
* had a fd for it.
*/
protected final boolean exists (String path)
{
if (super.shareStatus == ObjectStore.OS_UNSHARED)
{
if (FileSystemStore.fileCache.get(path) != null)
return true;
}
/*
* If here then we need to check the file system. If there, we will
* put it into the cache (if appropriate).
*/
File f = new File(path);
// files created but not yet written are normally considered to not exist yet. JBTM-821
boolean doesExist = (f.exists() && (scanZeroLengthFiles || f.length() > 0));
if (doesExist)
addToCache(path);
return doesExist;
}
protected final void addToCache (String fname)
{
if (super.shareStatus == ObjectStore.OS_UNSHARED)
{
FileSystemStore.fileCache.put(fname, fname);
}
}
protected final void removeFromCache (String fname)
{
removeFromCache(fname, true);
}
/**
* Print a warning if the file to be removed is not in the cache.
*
* @since 2.1.1.
*/
protected final void removeFromCache (String fname, boolean warn)
{
if (super.shareStatus == ObjectStore.OS_UNSHARED)
{
if ((FileSystemStore.fileCache.remove(fname) == null) && warn)
{
if (tsLogger.arjLoggerI18N.isWarnEnabled())
{
tsLogger.arjLoggerI18N.warn("com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore_2",
new Object[]{fname});
}
}
}
}
private final boolean present (String id, String[] list)
{
for (int i = 0; i < list.length; i++)
{
if (list[i].equals(id))
return true;
}
return false;
}
static final char unixSeparator = '/';
static boolean rewriteSeparator = false;
// allow derived classes to specify sync on a per instance basis
protected boolean syncWrites = true;
private String fullStoreName;
private String localStoreRoot;
private boolean isValid;
/*
* These values should be determined via something like pathconf
*/
private static final int MAXPNAMELEN = 255;
private static final int MAXNAMELENGTH = 255;
private static final int SLOP = 9;
// global values (some of which may be reset on a per instance basis).
private static boolean doSync = true;
protected static boolean scanZeroLengthFiles = false;
private static Hashtable fileCache = new Hashtable();
private static int createRetry = 100;
private static int createTimeout = 100;
static
{
String syncOpt = arjPropertyManager.propertyManager.getProperty(com.arjuna.ats.arjuna.common.Environment.OBJECTSTORE_SYNC);
if (syncOpt != null)
{
if (syncOpt.compareTo("OFF") == 0)
FileSystemStore.doSync = false;
}
else
FileSystemStore.doSync = true;
String scanZeroLengthFilesString = arjPropertyManager.propertyManager.getProperty(com.arjuna.ats.arjuna.common.Environment.SCAN_ZERO_LENGTH_FILES);
if("YES".equalsIgnoreCase(scanZeroLengthFilesString))
{
scanZeroLengthFiles = true;
}
if (File.separatorChar != FileSystemStore.unixSeparator)
rewriteSeparator = true;
String retry = arjPropertyManager.propertyManager.getProperty(com.arjuna.ats.arjuna.common.Environment.OBJECTSTORE_HIERARCHY_RETRY);
if (retry != null)
{
try
{
Integer i = new Integer(retry);
createRetry = i.intValue();
if (createRetry < 0)
createRetry = 100;
}
catch (NumberFormatException e)
{
throw new com.arjuna.ats.arjuna.exceptions.FatalError("Invalid retry for hierarchy creation: "+createRetry);
}
catch (Exception e)
{
throw new com.arjuna.ats.arjuna.exceptions.FatalError(e.toString());
}
}
String timeout = arjPropertyManager.propertyManager.getProperty(com.arjuna.ats.arjuna.common.Environment.OBJECTSTORE_HIERARCHY_TIMEOUT);
if (timeout != null)
{
try
{
Integer i = new Integer(timeout);
createTimeout = i.intValue();
if (createTimeout < 0)
createTimeout = 100;
}
catch (NumberFormatException e)
{
throw new com.arjuna.ats.arjuna.exceptions.FatalError("Invalid timeout for hierarchy creation: "+createTimeout);
}
catch (Exception e)
{
throw new com.arjuna.ats.arjuna.exceptions.FatalError(e.toString());
}
}
}
private static boolean isWindows = Utility.isWindows();
}