Oliver Zeigermann wrote:
We know the store is not in stable state, yet. So, please continue to report errors.

Next step to a stable store.


FIXES:

AbstractTxFileStoreService:
- Transaction will be marked for rollback upon system error or deadlock
- minor flaws

StoreLogger:
- logging of message and throwable will result in two log methods in Slide logging


TxFileContentStore:
- adaptions to new system error handling in AbstractTxFileStoreService
- streams get closed in finally blocks to assure all locks in FileResouceManager get freed
- minor flaws


TxXMLFileDescriptorsStore:
- adaptions to new system error handling in AbstractTxFileStoreService

XMLResourceDescriptor:
- adaptions to new system error handling in AbstractTxFileStoreService
- streams get closed in finally blocks to assure all locks in FileResouceManager get freed
- made it thread safe
- added a tiny hack (which is to be investigated further)


FileResourceManager:
- freeing locks and resource when tx is marked for rollback to avoid dangling locks when app misses to actually roll back the tx




Peter, would you...? I hardly dare to ask...

Thanks in advance,

Oliver
Index: AbstractTxFileStoreService.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-slide/src/stores/org/apache/slide/store/txfile/AbstractTxFileStoreService.java,v
retrieving revision 1.1
diff -u -w -r1.1 AbstractTxFileStoreService.java
--- AbstractTxFileStoreService.java     9 Oct 2003 09:31:33 -0000       1.1
+++ AbstractTxFileStoreService.java     24 Oct 2003 13:28:17 -0000
@@ -57,7 +57,11 @@
         new File(storeDir).mkdirs();
         new File(workDir).mkdirs();
 
-        rm = new FileResourceManager(storeDir, workDir, new StoreLogger(getLogger(), 
FileResourceManager.class.getName()));
+        rm =
+            new FileResourceManager(
+                storeDir,
+                workDir,
+                new StoreLogger(getLogger(), FileResourceManager.class.getName()));
 
         getLogger().log(
             "File Store configured to " + storeDir + ", working directory " + workDir,
@@ -134,7 +138,7 @@
             LOG_CHANNEL,
             Logger.DEBUG);
         try {
-            int status = rm.prepareTransaction(XidWrapper.wrap(xid));
+            int status = rm.prepareTransaction(txId);
             switch (status) {
                 case ResourceManager.PREPARE_SUCCESS_READONLY :
                     return XA_RDONLY;
@@ -266,6 +270,75 @@
         }
     }
 
+    public synchronized void throwInternalError(String cause) throws 
ServiceAccessException {
+        Object txId = getActiveTxId();
+
+        getLogger().log(
+            "Thread "
+                + Thread.currentThread()
+                + " marked transaction branch "
+                + txId
+                + " for rollback. Cause: "
+                + cause,
+            LOG_CHANNEL,
+            Logger.WARNING);
+
+        try {
+            rm.markTransactionForRollback(txId);
+        } catch (ResourceManagerException re) {
+            throw new ServiceAccessException(this, re);
+        }
+
+        throw new ServiceAccessException(this, cause);
+
+    }
+
+    // TODO if error is caused by lock that could not be acquired
+    // we should try deadlock detection instead of simply rolling back
+    // if no deadlock is detected, retrying for lock would be preferred method    
+    public synchronized void throwInternalError(Throwable cause) throws 
ServiceAccessException {
+        Object txId = getActiveTxId();
+
+        if ((cause instanceof ResourceManagerException)
+            && ((ResourceManagerException) cause).getStatus() == 
ResourceManagerException.ERR_NO_LOCK) {
+
+            // XXX strictly speaking, this is incorrect, as we actually did not chck 
for deadlock,
+            // but silently assume a deadlock must have been the cause for the failed 
lock
+            try {
+                rm.markTransactionForRollback(txId);
+            } catch (ResourceManagerException re) {
+                throw new ServiceAccessException(this, re);
+            }
+
+            getLogger().log(
+                "DEADLOCK VICTIM: Thread "
+                    + Thread.currentThread()
+                    + " marked transaction branch "
+                    + txId
+                    + " for rollback",
+                LOG_CHANNEL,
+                Logger.INFO);
+
+            throw new ServiceAccessException(this, "deadlock victim");
+
+        } else {
+
+            try {
+                rm.markTransactionForRollback(txId);
+            } catch (ResourceManagerException re) {
+                throw new ServiceAccessException(this, re);
+            }
+
+            getLogger().log(
+                "Thread " + Thread.currentThread() + " marked transaction branch " + 
txId + " for rollback",
+                LOG_CHANNEL,
+                Logger.WARNING);
+
+            throw new ServiceAccessException(this, cause);
+
+        }
+    }
+
     protected Object getActiveTxId() {
         Object txId = activeTransactionBranch.get();
         return txId;
Index: StoreLogger.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-slide/src/stores/org/apache/slide/store/txfile/StoreLogger.java,v
retrieving revision 1.1
diff -u -w -r1.1 StoreLogger.java
--- StoreLogger.java    9 Oct 2003 09:31:33 -0000       1.1
+++ StoreLogger.java    24 Oct 2003 13:28:17 -0000
@@ -37,9 +37,8 @@
 
     public void log(String message, int level, Throwable t) {
         if (logger != null) {
-            if (t == null) {
                 logger.log(message, logChannel, level);
-            } else {
+            if (t != null) {
                 logger.log(t, logChannel, level);
             }
         }
Index: TxFileContentStore.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-slide/src/stores/org/apache/slide/store/txfile/TxFileContentStore.java,v
retrieving revision 1.1
diff -u -w -r1.1 TxFileContentStore.java
--- TxFileContentStore.java     9 Oct 2003 09:31:33 -0000       1.1
+++ TxFileContentStore.java     24 Oct 2003 13:28:18 -0000
@@ -25,7 +25,7 @@
     public NodeRevisionContent retrieveRevisionContent(Uri uri, 
NodeRevisionDescriptor revisionDescriptor)
         throws ServiceAccessException, RevisionNotFoundException {
 
-        String revisionUri = revisionUri = uri.toString() + "_" + 
revisionDescriptor.getRevisionNumber();
+        String revisionUri = uri.toString() + "_" + 
revisionDescriptor.getRevisionNumber();
 
         try {
             Object txId = getActiveTxId();
@@ -42,7 +42,8 @@
             if (e.getStatus() == ResourceManagerException.ERR_NO_SUCH_RESOURCE) {
                 throw new RevisionNotFoundException(uri.toString(), 
revisionDescriptor.getRevisionNumber());
             } else {
-                throw new ServiceAccessException(this, e);
+                throwInternalError(e);
+                return null; // XXX fake (is never called)
             }
         }
     }
@@ -59,12 +60,12 @@
             storeRevisionContent(uri, revisionDescriptor, revisionContent);
         } catch (RevisionNotFoundException e) {
             // Can not be, as we just created it. If it unexpectedly is, this is 
fatal 
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
         } catch (ResourceManagerException e) {
             if (e.getStatus() == ResourceManagerException.ERR_RESOURCE_EXISTS) {
                 throw new RevisionAlreadyExistException(uri.toString(), 
revisionDescriptor.getRevisionNumber());
             } else {
-                throw new ServiceAccessException(this, e);
+                throwInternalError(e);
             }
         }
     }
@@ -76,28 +77,42 @@
         throws ServiceAccessException, RevisionNotFoundException {
         String revisionUri = revisionUri = uri.toString() + "_" + 
revisionDescriptor.getRevisionNumber();
 
+        OutputStream os = null;
+        InputStream is = null;
         try {
-            OutputStream os = rm.writeResource(getActiveTxId(), revisionUri);
-            InputStream is = revisionContent.streamContent();
+            os = rm.writeResource(getActiveTxId(), revisionUri);
+            is = revisionContent.streamContent();
 
             if (is != null) {
                 long contentBytes = FileHelper.copy(is, os);
-                os.close();
                 long contentLength = revisionDescriptor.getContentLength();
                 revisionDescriptor.setContentLength(contentBytes);
 
                 if (contentLength != -1 && contentBytes != contentLength) {
                     rm.deleteResource(getActiveTxId(), revisionUri);
-                    throw new ServiceAccessException(this, "Content length does not 
match expected");
+                    throwInternalError("Content length does not match expected");
                 }
             }
         } catch (IOException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
         } catch (ResourceManagerException e) {
             if (e.getStatus() == ResourceManagerException.ERR_NO_SUCH_RESOURCE) {
                 throw new RevisionNotFoundException(uri.toString(), 
revisionDescriptor.getRevisionNumber());
             } else {
-                throw new ServiceAccessException(this, e);
+                throwInternalError(e);
+            }
+        } finally {
+            try {
+                if (os != null) {
+                    os.close();
+                }
+            } catch (IOException e) {
+            }
+            try {
+                if (is != null) {
+                    is.close();
+                }
+            } catch (IOException e) {
             }
         }
     }
@@ -108,7 +123,7 @@
         try {
             rm.deleteResource(getActiveTxId(), revisionUri);
         } catch (ResourceManagerException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
         }
     }
 
Index: TxXMLFileDescriptorsStore.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-slide/src/stores/org/apache/slide/store/txfile/TxXMLFileDescriptorsStore.java,v
retrieving revision 1.1
diff -u -w -r1.1 TxXMLFileDescriptorsStore.java
--- TxXMLFileDescriptorsStore.java      9 Oct 2003 09:31:33 -0000       1.1
+++ TxXMLFileDescriptorsStore.java      24 Oct 2003 13:28:18 -0000
@@ -64,7 +64,7 @@
             xfd.storeObject(uri, object);
         } catch (ObjectNotFoundException e) {
             // should not happen, if it does, it is an error inside this store:
-            throw new ServiceAccessException(this, "Newly created file vanished");
+            throwInternalError("Newly created file vanished");
         }
     }
 
@@ -84,7 +84,7 @@
             XMLResourceDescriptor xfd = getFileDescriptor(uri);
             xfd.grantPermission(uri, permission);
         } catch (ObjectNotFoundException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
         }
     }
 
@@ -93,7 +93,7 @@
             XMLResourceDescriptor xfd = getFileDescriptor(uri);
             xfd.revokePermission(uri, permission);
         } catch (ObjectNotFoundException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
         }
     }
 
@@ -102,7 +102,7 @@
             XMLResourceDescriptor xfd = getFileDescriptor(uri);
             xfd.revokePermissions(uri);
         } catch (ObjectNotFoundException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
         }
     }
 
@@ -111,7 +111,8 @@
             XMLResourceDescriptor xfd = getFileDescriptor(uri);
             return xfd.enumeratePermissions();
         } catch (ObjectNotFoundException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
+            return null; // XXX fake (is never called)
         }
     }
 
@@ -126,7 +127,7 @@
             XMLResourceDescriptor xfd = getFileDescriptor(uri);
             xfd.putLock(uri, lock);
         } catch (ObjectNotFoundException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
         }
     }
 
@@ -135,7 +136,7 @@
             XMLResourceDescriptor xfd = getFileDescriptor(uri);
             xfd.renewLock(uri, lock);
         } catch (ObjectNotFoundException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
         }
     }
 
@@ -157,7 +158,8 @@
             XMLResourceDescriptor xfd = getFileDescriptor(uri);
             return xfd.enumerateLocks();
         } catch (ObjectNotFoundException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
+            return null; // XXX fake (is never called)
         }
     }
 
@@ -183,7 +185,7 @@
             XMLResourceDescriptor xfd = getFileDescriptor(uri);
             xfd.createRevisionDescriptors(uri, revisionDescriptors);
         } catch (ObjectNotFoundException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
         }
     }
 
@@ -202,7 +204,7 @@
             XMLResourceDescriptor xfd = getFileDescriptor(uri);
             xfd.removeRevisionDescriptors(uri);
         } catch (ObjectNotFoundException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
         }
     }
 
@@ -228,7 +230,7 @@
             XMLResourceDescriptor xfd = getFileDescriptor(uri);
             xfd.createRevisionDescriptor(uri, revisionDescriptor);
         } catch (ObjectNotFoundException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
         }
     }
 
@@ -247,7 +249,7 @@
             XMLResourceDescriptor xfd = getFileDescriptor(uri);
             xfd.removeRevisionDescriptor(uri, number);
         } catch (ObjectNotFoundException e) {
-            throw new ServiceAccessException(this, e);
+            throwInternalError(e);
         }
     }
 
@@ -260,10 +262,9 @@
     /**
      * Either returns a cached file descriptor or loads it from DB 
      */
-    protected XMLResourceDescriptor getFileDescriptor(Uri uri)
-        throws ServiceAccessException, ObjectNotFoundException {
+    protected XMLResourceDescriptor getFileDescriptor(Uri uri) throws 
ServiceAccessException, ObjectNotFoundException {
         Object txId = getActiveTxId();
-        XMLResourceDescriptor xfd = new XMLResourceDescriptor(uri, rm, txId, 
characterEncoding);
+        XMLResourceDescriptor xfd = new XMLResourceDescriptor(uri, this, rm, txId, 
characterEncoding);
         return xfd;
     }
 }
Index: XMLResourceDescriptor.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-slide/src/stores/org/apache/slide/store/txfile/XMLResourceDescriptor.java,v
retrieving revision 1.1
diff -u -w -r1.1 XMLResourceDescriptor.java
--- XMLResourceDescriptor.java  9 Oct 2003 09:31:33 -0000       1.1
+++ XMLResourceDescriptor.java  24 Oct 2003 13:28:20 -0000
@@ -40,9 +40,10 @@
 
     protected static final String PATH_EXTENSION = ".def.xml";
     protected final FileResourceManager rm;
+    protected final TxXMLFileDescriptorsStore store;
     protected final String characterEncoding;
-    protected final Object txId;
-    protected final Uri uri;
+    protected volatile Object txId;
+    protected volatile Uri uri;
     protected final String loadPath;
 
     protected StoreLogger logger;
@@ -57,7 +58,12 @@
      * @throws ServiceAccessException if anything goes wrong at system level
      * @throws ObjectNotFoundException if <code>load</code> is set to 
<code>true</code> and the descriptor is not present in resource manager
      */
-    public XMLResourceDescriptor(Uri uri, FileResourceManager rm, Object txId, String 
characterEncoding)
+    public XMLResourceDescriptor(
+        Uri uri,
+        TxXMLFileDescriptorsStore store,
+        FileResourceManager rm,
+        Object txId,
+        String characterEncoding)
         throws ServiceAccessException, ObjectNotFoundException {
         // XXX super class tries to create folders, no way to stop it:
         // at least let it create folders in a place where it can do no harm
@@ -66,6 +72,7 @@
         logger = 
rm.getLogger().cloneWithNewLogChannel(XMLResourceDescriptor.class.getName());
 
         this.rm = rm;
+        this.store = store;
         this.characterEncoding = characterEncoding;
         this.txId = txId;
         this.uri = uri;
@@ -79,22 +86,28 @@
      * @throws ServiceAccessException if anything goes wrong at system level
      * @throws ObjectNotFoundException if the descriptor has not been created before 
      */
-    public void save() throws ServiceAccessException, ObjectNotFoundException {
+    public synchronized void save() throws ServiceAccessException, 
ObjectNotFoundException {
         if (txId == null) {
-            throw new ServiceAccessException(null, "Not inside tx");
+            store.throwInternalError("Not inside tx");
         }
         logger.logFine("Tx " + txId + " saves data for " + loadPath);
+
+        OutputStream os = null;
         try {
-            OutputStream os = rm.writeResource(txId, loadPath);
+            os = rm.writeResource(txId, loadPath);
             save(os);
-            os.close();
-        } catch (IOException e) {
-            throw new ServiceAccessException(null, e);
         } catch (ResourceManagerException e) {
             if (e.getStatus() == ResourceManagerException.ERR_NO_SUCH_RESOURCE) {
                 throw new ObjectNotFoundException(uri);
             } else {
-                throw new ServiceAccessException(null, e);
+                store.throwInternalError(e);
+            }
+        } finally {
+            try {
+                if (os != null) {
+                    os.close();
+                }
+            } catch (IOException e) {
             }
         }
     }
@@ -105,10 +118,10 @@
      * @throws ServiceAccessException if anything goes wrong at system level
      * @throws ObjectAlreadyExistsException if the descriptor already exists 
      */
-    public void create() throws ServiceAccessException, ObjectAlreadyExistsException {
+    public synchronized void create() throws ServiceAccessException, 
ObjectAlreadyExistsException {
         logger.logFiner("Tx " + txId + " creates " + loadPath);
         if (txId == null) {
-            throw new ServiceAccessException(null, "Not inside tx");
+            store.throwInternalError("Not inside tx");
         }
         try {
             rm.createResource(txId, loadPath, false);
@@ -117,7 +130,7 @@
             if (e.getStatus() == ResourceManagerException.ERR_RESOURCE_EXISTS) {
                 throw new ObjectAlreadyExistsException(uri.toString());
             } else {
-                throw new ServiceAccessException(null, e);
+                store.throwInternalError(e);
             }
         }
     }
@@ -128,10 +141,10 @@
      * @throws ServiceAccessException if anything goes wrong at system level
      * @throws ObjectNotFoundException if the descriptor does not exist 
      */
-    public void delete() throws ServiceAccessException, ObjectNotFoundException {
+    public synchronized void delete() throws ServiceAccessException, 
ObjectNotFoundException {
         logger.logFiner("Tx " + txId + " deletes " + loadPath);
         if (txId == null) {
-            throw new ServiceAccessException(null, "Not inside tx");
+            store.throwInternalError("Not inside tx");
         }
         try {
             rm.deleteResource(txId, loadPath, false);
@@ -140,7 +153,7 @@
             if (e.getStatus() == ResourceManagerException.ERR_NO_SUCH_RESOURCE) {
                 throw new ObjectNotFoundException(uri.toString());
             } else {
-                throw new ServiceAccessException(null, e);
+                store.throwInternalError(e);
             }
         }
     }
@@ -151,34 +164,39 @@
      * @throws ServiceAccessException if anything goes wrong at system level
      * @throws ObjectNotFoundException if the descriptor does not exist 
      */
-    public void load() throws ServiceAccessException, ObjectNotFoundException {
+    public synchronized void load() throws ServiceAccessException, 
ObjectNotFoundException {
         logger.logFiner("Tx " + txId + " loads data for " + loadPath);
+
+        InputStream is = null;
         try {
             logger.logFinest("Faking read access from outside tx for " + loadPath);
             if (txId != null) {
                 if (rm.resourceExists(txId, loadPath)) {
-                    InputStream is = rm.readResource(txId, loadPath);
+                    is = rm.readResource(txId, loadPath);
                     load(is);
-                    is.close();
                 } else {
                     init();
                 }
             } else {
                 if (rm.resourceExists(loadPath)) {
-                    InputStream is = rm.readResource(loadPath);
+                    is = rm.readResource(loadPath);
                     load(is);
-                    is.close();
                 } else {
                     init();
                 }
             }
-        } catch (IOException e) {
-            throw new ServiceAccessException(null, e);
         } catch (ResourceManagerException e) {
             if (e.getStatus() == ResourceManagerException.ERR_NO_SUCH_RESOURCE) {
                 throw new ObjectNotFoundException(uri);
             } else {
-                throw new ServiceAccessException(null, e);
+                store.throwInternalError(e);
+            }
+        } finally {
+            try {
+                if (is != null) {
+                    is.close();
+                }
+            } catch (IOException e) {
             }
         }
     }
@@ -208,7 +226,7 @@
      * @param o object to compare this descriptor to
      * @return <code>true</code> if object is equal as described above 
      */
-    public boolean equals(Object o) {
+    public synchronized boolean equals(Object o) {
         return (
             this == o
                 || (o != null
@@ -217,7 +235,7 @@
                     && ((XMLResourceDescriptor) o).txId.equals(txId)));
     }
 
-    protected void save(OutputStream os) throws ServiceAccessException {
+    protected synchronized void save(OutputStream os) throws ServiceAccessException {
         Element aRoot = encode();
         Document aDocument = new Document(aRoot);
 
@@ -230,23 +248,23 @@
             aOutputter.output(aDocument, os);
             os.flush();
         } catch (IOException e) {
-            throw new ServiceAccessException(null, e);
+            store.throwInternalError(e);
         }
     }
 
-    protected void load(InputStream is) throws ServiceAccessException {
+    protected synchronized void load(InputStream is) throws ServiceAccessException {
         SAXBuilder aBuilder = new SAXBuilder();
         try {
             Document aDocument = aBuilder.build(is);
             decode(aDocument.getRootElement());
         } catch (JDOMException e) {
-            throw new ServiceAccessException(null, e);
+            store.throwInternalError(e);
         } catch (IOException e) {
-            throw new ServiceAccessException(null, e);
+            store.throwInternalError(e);
         }
     }
 
-    protected void init() throws ServiceAccessException {
+    protected synchronized void init() throws ServiceAccessException {
         object = null;
         permissions = new Vector();
         locks = new Vector();
@@ -254,14 +272,20 @@
         descriptor = new Hashtable();
     }
 
-    protected void save(Uri uri) throws ServiceAccessException {
+    protected synchronized void save(Uri uri) throws ServiceAccessException {
         if (txId == null) {
-            throw new ServiceAccessException(null, "Not inside tx");
+            store.throwInternalError("Not inside tx");
         }
+        // XXX this is a HACK, should throw exception, really 
+        //      if (object == null) {
+        //          store.throwInternalError("Resource '"+uri+"' not initialized");
+        //      }
+        if (object == null)
+            return;
         try {
             save();
         } catch (ObjectNotFoundException e) {
-            throw new ServiceAccessException(null, e);
+            store.throwInternalError(e);
         }
     }
 
Index: rm/impl/FileResourceManager.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-slide/src/stores/org/apache/slide/store/txfile/rm/impl/FileResourceManager.java,v
retrieving revision 1.1
diff -u -w -r1.1 FileResourceManager.java
--- rm/impl/FileResourceManager.java    9 Oct 2003 09:31:33 -0000       1.1
+++ rm/impl/FileResourceManager.java    24 Oct 2003 13:28:22 -0000
@@ -448,8 +448,13 @@
     public void markTransactionForRollback(Object txId) throws 
ResourceManagerException {
         assureRMReady();
         TransactionContext context = txInitialSaneCheckForWriting(txId);
+        try {
         context.status = STATUS_MARKED_ROLLBACK;
         context.saveState();
+        } finally {
+            // be very sure to free locks and resources, as application might crash 
or otherwise forget to roll this tx back
+            context.finalCleanUp();
+        }
     }
 
     public int prepareTransaction(Object txId) throws ResourceManagerException {

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to