[jboss-svn-commits] JBL Code SVN: r36506 - in labs/jbosstm/trunk/ArjunaCore/arjuna: classes/com/arjuna/ats/internal/arjuna/objectstore and 1 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Fri Jan 7 05:20:34 EST 2011


Author: jhalliday
Date: 2011-01-07 05:20:34 -0500 (Fri, 07 Jan 2011)
New Revision: 36506

Added:
   labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/
   labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqJournalEnvironmentBean.java
   labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqJournalEnvironmentBeanMBean.java
   labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqJournalStore.java
   labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqObjectStoreAdaptor.java
Modified:
   labs/jbosstm/trunk/ArjunaCore/arjuna/build.xml
Log:
Add HornetQ Journal based objectstore impl to trunk. JBTM-782


Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/build.xml
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/build.xml	2011-01-06 23:23:30 UTC (rev 36505)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/build.xml	2011-01-07 10:20:34 UTC (rev 36506)
@@ -22,6 +22,8 @@
 
     <property name="modulename" value="arjuna"/>
 
+    <property name="global.ext.libs" value="hornetq-core.jar,jboss-logging.jar"/><!-- jboss-logging-tools.jar -->
+
     <import file="../../sharedbuild.xml"/>
 
     <target name="init" depends="sharedbuild.init">
@@ -40,7 +42,7 @@
             </additional.classpath>
         </compile-tests.macro>
     </target>
-    
+
 	<!--
 		run tests that match a given pattern, for example
 		ant testone -DONECLASS="**/*ObjectStoreAPIJMXTest.java"

Added: labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqJournalEnvironmentBean.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqJournalEnvironmentBean.java	                        (rev 0)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqJournalEnvironmentBean.java	2011-01-07 10:20:34 UTC (rev 36506)
@@ -0,0 +1,287 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * 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) 2010,
+ * @author JBoss, by Red Hat.
+ */
+package com.arjuna.ats.internal.arjuna.objectstore.hornetq;
+
+import com.arjuna.common.internal.util.propertyservice.PropertyPrefix;
+
+import java.io.File;
+
+/**
+ * A JavaBean containing assorted configuration properties for the HornetQ Journal based transaction logging system.
+ *
+ * Parameters on this file serve a similar role to their counterparts in HornetQ.
+ * The HornetQ docs therefore provide relevant information on usage:
+ * http://hornetq.sourceforge.net/docs/hornetq-2.1.1.Final/user-manual/en/html/persistence.html#configuring.message.journal.journal-type
+ *
+ * @author Jonathan Halliday (jonathan.halliday at redhat.com), 2010-03
+ */
+ at PropertyPrefix(prefix = "com.arjuna.ats.arjuna.hornetqjournal.")
+public class HornetqJournalEnvironmentBean implements HornetqJournalEnvironmentBeanMBean
+{
+    private volatile int fileSize = 1024*1024*2;
+
+    private volatile int minFiles = 4;
+
+    private volatile int compactMinFiles = 10;
+
+    private volatile int compactPercentage = 30;
+
+    private volatile String filePrefix = "jbossts";
+
+    private volatile String fileExtension = "txlog";
+
+    private volatile int maxIO = 1;
+
+    private volatile String storeDir = System.getProperty("user.dir") + File.separator + "HornetqJournalStore";
+
+    private volatile boolean syncWrites = true;
+
+    private volatile boolean syncDeletes = true;
+
+
+    /**
+     * Returns the desired size in bytes of each log file.
+     * Minimum 1024.
+     *
+     * Default: 2MB (2097152 bytes)
+     *
+     * @return The individual log file size, in bytes.
+     */
+    public int getFileSize()
+    {
+        return fileSize;
+    }
+
+    /**
+     * Sets the desired size in bytes for each log file.
+     * 
+     * @param fileSize the individual log file size, in bytes.
+     */
+    public void setFileSize(int fileSize)
+    {
+        this.fileSize = fileSize;
+    }
+
+    /**
+     * Returns the minimum number of log files to use.
+     * Minimum 2.
+     *
+     * Default: 4
+     *
+     * @return the minimum number of individual log files.
+     */
+    public int getMinFiles()
+    {
+        return minFiles;
+    }
+
+    /**
+     * Sets the minimum number of log files to use.
+     *
+     * @param minFiles the minimum number of individual log files.
+     */
+    public void setMinFiles(int minFiles)
+    {
+        this.minFiles = minFiles;
+    }
+
+    /**
+     * Gets the minimal number of files before we can consider compacting.
+     *
+     * Default: 10
+     *
+     * @return the threshold file count.
+     */
+    public int getCompactMinFiles()
+    {
+        return compactMinFiles;
+    }
+
+    /**
+     * Sets the minimal number of files before we can consider compacting.
+     *
+     * @param compactMinFiles the threshold file count.
+     */
+    public void setCompactMinFiles(int compactMinFiles)
+    {
+        this.compactMinFiles = compactMinFiles;
+    }
+
+    /**
+     * Gets the percentage minimum capacity usage at which to start compacting.
+     *
+     * Default: 30
+     *
+     * @return the threshold percentage.
+     */
+    public int getCompactPercentage()
+    {
+        return compactPercentage;
+    }
+
+    /**
+     * Sets the percentage minimum capacity usage at which to start compacting.
+     *
+     * @param compactPercentage the threshold percentage.
+     */
+    public void setCompactPercentage(int compactPercentage)
+    {
+        this.compactPercentage = compactPercentage;
+    }
+
+    /**
+     * Returns the prefix to be used when naming each log file.
+     *
+     * Default: "jbossts"
+     *
+     * @return the prefix used to construct individual log file names.
+     */
+    public String getFilePrefix()
+    {
+        return filePrefix;
+    }
+
+    /**
+     * Sets the prefix to be used when naming each log file.
+     *
+     * @param filePrefix the prefix used to construct individual log file names.
+     */
+    public void setFilePrefix(String filePrefix)
+    {
+        this.filePrefix = filePrefix;
+    }
+
+    /**
+     * Returns the suffix to be used then naming each log file.
+     *
+     * Default: "txlog"
+     *
+     * @return the suffix used to construct individual log file names.
+     */
+    public String getFileExtension()
+    {
+        return fileExtension;
+    }
+
+    /**
+     * Sets the suffix to be used when naming each log file.
+     *
+     * @param fileExtension the suffix used to construct individual log file names.
+     */
+    public void setFileExtension(String fileExtension)
+    {
+        this.fileExtension = fileExtension;
+    }
+
+    /**
+     * Gets the maximum write requests queue depth.
+     * Minimum 1. Use 1 for NIO. For AIO, recommended 500.
+     *
+     * Default: 1
+     *
+     * @return the max number of outstanding requests.
+     */
+    public int getMaxIO()
+    {
+        return maxIO;
+    }
+
+    /**
+     * Sets the maximum write requests queue depth.
+     *
+     * @param maxIO the max number of outstanding requests.
+     */
+    public void setMaxIO(int maxIO)
+    {
+        this.maxIO = maxIO;
+    }
+
+    /**
+     * Returns the log directory path
+     *
+     * Default: {user.dir}/HornetqJournalStore
+     *
+     * @return the log directory name
+     */
+    public String getStoreDir()
+    {
+        return storeDir;
+    }
+
+    /**
+     * Sets the log directory path.
+     *
+     * @param storeDir the path to the log directory.
+     */
+    public void setStoreDir(String storeDir)
+    {
+        this.storeDir = storeDir;
+    }
+
+    /**
+     * Returns the sync setting for transaction log write operations.
+     * To preserve ACID properties this value must be set to true, in which case
+     * log write operations block until data is forced to the physical storage device.
+     * Turn sync off only if you don't care about data integrity.
+     *
+     * Default: true.
+     *
+     * @return true if log writes should be synchronous, false otherwise.
+     */
+    public boolean isSyncWrites()
+    {
+        return syncWrites;
+    }
+
+    /**
+     * Sets if log write operations should be synchronous or not.
+     *
+     * @param syncWrites true for synchronous operation, false otherwise.
+     */
+    public void setSyncWrites(boolean syncWrites)
+    {
+        this.syncWrites = syncWrites;
+    }
+
+    /**
+     * Returns the sync setting for transaction log delete operations.
+     * For optimal crash recovery this value should be set to true.
+     * Asynchronous deletes may give rise to unnecessary crash recovery complications.
+     *
+     * Default: true.
+     * 
+     * @return true if log deletes should be synchronous, false otherwise.
+     */
+    public boolean isSyncDeletes()
+    {
+        return syncDeletes;
+    }
+
+    /**
+     * Sets if log delete operations should be synchronous or not.
+     *
+     * @param syncDeletes true for synchronous operation, false otherwise.
+     */
+    public void setSyncDeletes(boolean syncDeletes)
+    {
+        this.syncDeletes = syncDeletes;
+    }
+}

Added: labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqJournalEnvironmentBeanMBean.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqJournalEnvironmentBeanMBean.java	                        (rev 0)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqJournalEnvironmentBeanMBean.java	2011-01-07 10:20:34 UTC (rev 36506)
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * 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) 2010,
+ * @author JBoss, by Red Hat.
+ */
+package com.arjuna.ats.internal.arjuna.objectstore.hornetq;
+
+/**
+ * A JMX MBean interface containing configuration for the HornetQ Journal based transaction logging system.
+ *
+ * @author Jonathan Halliday (jonathan.halliday at redhat.com)
+ */
+public interface HornetqJournalEnvironmentBeanMBean
+{
+    public int getFileSize();
+
+    public int getMinFiles();
+
+    public int getCompactMinFiles();
+
+    public int getCompactPercentage();
+
+    public String getFilePrefix();
+
+    public String getFileExtension();
+
+    public int getMaxIO();
+
+    public String getStoreDir();
+
+    public boolean isSyncWrites();
+
+    public boolean isSyncDeletes();
+}

Added: labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqJournalStore.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqJournalStore.java	                        (rev 0)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqJournalStore.java	2011-01-07 10:20:34 UTC (rev 36506)
@@ -0,0 +1,256 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * 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) 2010,
+ * @author JBoss, by Red Hat.
+ */
+package com.arjuna.ats.internal.arjuna.objectstore.hornetq;
+
+import com.arjuna.ats.arjuna.state.InputObjectState;
+import com.arjuna.ats.arjuna.state.OutputObjectState;
+import com.arjuna.ats.arjuna.state.OutputBuffer;
+import com.arjuna.ats.arjuna.state.InputBuffer;
+import com.arjuna.ats.arjuna.exceptions.ObjectStoreException;
+import com.arjuna.ats.arjuna.common.Uid;
+
+import com.arjuna.ats.internal.arjuna.common.UidHelper;
+import org.hornetq.core.journal.*;
+import org.hornetq.core.journal.impl.JournalImpl;
+import org.hornetq.core.journal.impl.AIOSequentialFileFactory;
+import org.hornetq.core.journal.impl.NIOSequentialFileFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Implementation of the tx store backed by HornetQ's journal.
+ * This is a bean suitable for hooking into the app server lifecycle.
+ *
+ * @author Jonathan Halliday (jonathan.halliday at redhat.com), 2010-03
+ */
+public class HornetqJournalStore
+{
+    private final Journal journal;
+
+    private final ConcurrentMap<String,Map<Uid, RecordInfo>> content = new ConcurrentHashMap<String, Map<Uid, RecordInfo>>();
+
+    private final Object uidMappingLock = new Object();
+    private final boolean syncWrites;
+    private final boolean syncDeletes;
+    private long maxID = 0;
+
+    private final String storeDirCanonicalPath;
+    
+    private static final byte RECORD_TYPE = 0x00;
+
+    public void stop() throws Exception {
+        journal.stop();
+    }
+
+    public void start() throws Exception {
+
+        journal.start();
+
+        List<RecordInfo> committedRecords = new LinkedList<RecordInfo>();
+        List<PreparedTransactionInfo> preparedTransactions = new LinkedList<PreparedTransactionInfo>();
+        TransactionFailureCallback failureCallback = new TransactionFailureCallback() {
+            public void failedTransaction(long l, java.util.List<org.hornetq.core.journal.RecordInfo> recordInfos, java.util.List<org.hornetq.core.journal.RecordInfo> recordInfos1) {
+                System.err.println("This should never get called");
+            }
+        };
+
+        JournalLoadInformation journalLoadInformation = journal.load(committedRecords, preparedTransactions, failureCallback);
+        maxID = journalLoadInformation.getMaxID();
+
+        if(!preparedTransactions.isEmpty()) {
+            System.err.println("This should never happen");
+        }
+
+        for(RecordInfo record : committedRecords) {
+            InputBuffer inputBuffer = new InputBuffer(record.data);
+            Uid uid = UidHelper.unpackFrom(inputBuffer);
+            String typeName = inputBuffer.unpackString();
+            getContentForType(typeName).put(uid, record);
+            // don't unpack the rest yet, we may never need it. read_committed does it on demand.
+        }
+
+        System.out.println("HornetqJournalStore started foo");
+    }
+
+    public HornetqJournalStore(HornetqJournalEnvironmentBean envBean) throws IOException {
+
+        System.out.println("HornetqJournalStore ctor");
+
+        syncWrites = envBean.isSyncWrites();
+        syncDeletes = envBean.isSyncDeletes();
+
+        File storeDir = new File(envBean.getStoreDir());
+        if(!storeDir.exists() && !storeDir.mkdirs()) {
+            throw new IOException("Failed to create store dir "+storeDir.getCanonicalPath()); // TODO i18n
+        }
+        storeDirCanonicalPath = storeDir.getCanonicalPath();
+
+        SequentialFileFactory sequentialFileFactory;
+        if(AIOSequentialFileFactory.isSupported()) {
+            sequentialFileFactory = new AIOSequentialFileFactory(envBean.getStoreDir());
+        } else {
+            sequentialFileFactory = new NIOSequentialFileFactory(envBean.getStoreDir());
+        }
+
+        journal = new JournalImpl(envBean.getFileSize(), envBean.getMinFiles(), envBean.getCompactMinFiles(),
+                        envBean.getCompactPercentage(), sequentialFileFactory, envBean.getFilePrefix(),
+                        envBean.getFileExtension(), envBean.getMaxIO());
+    }
+
+
+    /**
+     * Remove the object's committed state.
+     *
+     * @param uid  The object to work on.
+     * @param typeName The type of the object to work on.
+     * @return <code>true</code> if no errors occurred, <code>false</code>
+     *         otherwise.
+     * @throws ObjectStoreException if things go wrong.
+     */
+    public boolean remove_committed(Uid uid, String typeName) throws ObjectStoreException
+    {
+        try {
+            long id = getId(uid, typeName); // look up the id *before* doing the remove from state, or it won't be there any more.
+            getContentForType(typeName).remove(uid);
+            journal.appendDeleteRecord(id, syncDeletes);
+        } catch(Exception e) {
+            throw new ObjectStoreException(e);
+        }
+
+        return true;
+    }
+
+    /**
+     * Write a new copy of the object's committed state.
+     *
+     * @param uid    The object to work on.
+     * @param typeName   The type of the object to work on.
+     * @param txData The state to write.
+     * @return <code>true</code> if no errors occurred, <code>false</code>
+     *         otherwise.
+     * @throws ObjectStoreException if things go wrong.
+     */
+    public boolean write_committed(Uid uid, String typeName, OutputObjectState txData) throws ObjectStoreException
+    {
+        try {
+            OutputBuffer outputBuffer = new OutputBuffer();
+            UidHelper.packInto(uid, outputBuffer);
+            outputBuffer.packString(typeName);
+            outputBuffer.packBytes(txData.buffer());
+            long id = getId(uid, typeName);
+            byte[] data = outputBuffer.buffer();
+
+            // yup, there is a race condition here.
+            if(getContentForType(typeName).containsKey(uid)) {
+                journal.appendUpdateRecord(id, RECORD_TYPE, data, syncWrites);
+            } else {
+                journal.appendAddRecord(id, RECORD_TYPE, data, syncWrites);
+            }
+
+            RecordInfo record = new RecordInfo(id, RECORD_TYPE, data, false);
+            getContentForType(typeName).put(uid, record);
+        } catch(Exception e) {
+            throw new ObjectStoreException(e);
+        }
+
+        return true;
+    }
+
+    /**
+     * Read the object's committed state.
+     *
+     * @param uid  The object to work on.
+     * @param typeName The type of the object to work on.
+     * @return the state of the object.
+     * @throws ObjectStoreException if things go wrong.
+     */
+    public InputObjectState read_committed(Uid uid, String typeName) throws ObjectStoreException
+    {
+        RecordInfo record = getContentForType(typeName).get(uid);
+        if(record == null) {
+            return null;
+        }
+
+        // this repeated unpacking is a little inefficient - subclass RecordInfo to hold unpacked form too?
+        // not too much of an issue as log reads are done for recovery only.
+        try {
+            InputBuffer inputBuffer = new InputBuffer(record.data);
+            Uid unpackedUid = UidHelper.unpackFrom(inputBuffer);
+            String unpackedTypeName = inputBuffer.unpackString();
+            InputObjectState inputObjectState = new InputObjectState(uid, typeName, inputBuffer.unpackBytes());
+            return inputObjectState;
+        } catch(Exception e) {
+            throw new ObjectStoreException(e);
+        }
+    }
+
+    public boolean contains(Uid uid, String typeName) {
+        RecordInfo record = getContentForType(typeName).get(uid);
+        return record != null;
+    }
+
+    /**
+     * @return the "name" of the object store. Where in the hierarchy it appears, e.g., /ObjectStore/MyName/...
+     */
+    public String getStoreName()
+    {
+        return this.getClass().getSimpleName()+":"+storeDirCanonicalPath;
+    }
+
+    public String[] getKnownTypes() {
+        return content.keySet().toArray(new String[content.size()]);
+    }
+
+    public Uid[] getUidsForType(String typeName) {
+        Set<Uid> keySet = getContentForType(typeName).keySet();
+        return keySet.toArray(new Uid[keySet.size()]);
+    }
+
+    /////////////////////////////////
+
+    private Map<Uid, RecordInfo> getContentForType(String typeName) {
+        Map<Uid, RecordInfo> result = content.get(typeName);
+        if(result == null) {
+            content.putIfAbsent(typeName, new ConcurrentHashMap<Uid, RecordInfo>());
+            result = content.get(typeName);
+        }
+        return result;
+    }
+
+    private long getId(Uid uid, String typeName) {
+        synchronized (uidMappingLock) {
+            RecordInfo record = getContentForType(typeName).get(uid);
+            if(record != null) {
+                return record.id;
+            } else {
+                maxID++;
+                return maxID;
+            }
+        }
+    }
+}

Added: labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqObjectStoreAdaptor.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqObjectStoreAdaptor.java	                        (rev 0)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/objectstore/hornetq/HornetqObjectStoreAdaptor.java	2011-01-07 10:20:34 UTC (rev 36506)
@@ -0,0 +1,417 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * 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) 2010,
+ * @author JBoss, by Red Hat.
+ */
+package com.arjuna.ats.internal.arjuna.objectstore.hornetq;
+
+import com.arjuna.ats.arjuna.common.Uid;
+import com.arjuna.ats.arjuna.exceptions.ObjectStoreException;
+import com.arjuna.ats.arjuna.objectstore.ObjectStoreAPI;
+import com.arjuna.ats.arjuna.objectstore.StateStatus;
+import com.arjuna.ats.arjuna.state.InputObjectState;
+import com.arjuna.ats.arjuna.state.OutputObjectState;
+import com.arjuna.ats.internal.arjuna.common.UidHelper;
+import com.arjuna.common.internal.util.propertyservice.BeanPopulator;
+
+import java.io.IOException;
+import java.io.SyncFailedException;
+import java.util.HashSet;
+import java.util.Set;
+
+/* transaction-jboss-beans.xml:
+
+    <bean name="HornetqJournalEnvironmentBean" class="com.arjuna.ats.internal.arjuna.objectstore.hornetq.HornetqJournalEnvironmentBean">
+        <property name="storeDir">${jboss.server.data.dir}/tx-object-store/HornetqJournalStore</property>
+    </bean>
+    <bean name="HornetqJournalStore" class="com.arjuna.ats.internal.arjuna.objectstore.hornetq.HornetqJournalStore">
+        <constructor>
+            <parameter><inject bean="HornetqJournalEnvironmentBean"/></parameter>
+        </constructor>
+    </bean>
+    <bean name="HornetqObjectStoreAdaptor" class="com.arjuna.ats.internal.arjuna.objectstore.hornetq.HornetqObjectStoreAdaptor">
+        <constructor>
+            <parameter><inject bean="HornetqJournalStore"/></parameter>
+        </constructor>
+    </bean>
+    <bean name="TxStoreManager" class="com.arjuna.ats.arjuna.objectstore.StoreManager">
+        <constructor>
+            <parameter><inject bean="HornetqObjectStoreAdaptor"/></parameter>
+            <parameter><null/></parameter>
+        </constructor>
+    </bean>
+
+    TODO wire to RecMgr/TxMgr lifecycle deps
+
+*/
+
+/**
+ * Adaptor class that wraps the store to make it look like an ObjectStore.
+ *
+ * @author Jonathan Halliday (jonathan.halliday at redhat.com), 2010-03
+ */
+public class HornetqObjectStoreAdaptor implements ObjectStoreAPI
+{
+    private final HornetqJournalStore store;
+
+    // used for standalone bootstrap via StoreManager
+    public HornetqObjectStoreAdaptor() throws IOException {
+
+        HornetqJournalEnvironmentBean envBean = BeanPopulator.getDefaultInstance(HornetqJournalEnvironmentBean.class);
+
+        this.store = new HornetqJournalStore(envBean);
+    }
+
+    // used for beans wiring type bootstrap when running embedded.
+    public HornetqObjectStoreAdaptor(HornetqJournalStore store) {
+        this.store = store;
+    }
+
+    @Override
+    public void start()
+    {
+        try {
+            store.start();
+        } catch(Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void stop()
+    {
+        try {
+            store.stop();
+        } catch(Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Read the object's shadowed state.
+     *
+     * @param u  The object to work on.
+     * @param tn The type of the object to work on.
+     * @return the state of the object.
+     */
+    @Override
+    public InputObjectState read_uncommitted(Uid u, String tn) throws ObjectStoreException
+    {
+        throw new ObjectStoreException("This should never be called");
+    }
+
+    /**
+     * Remove the object's uncommitted state.
+     *
+     * @param u  The object to work on.
+     * @param tn The type of the object to work on.
+     * @return <code>true</code> if no errors occurred, <code>false</code>
+     *         otherwise.
+     */
+    @Override
+    public boolean remove_uncommitted(Uid u, String tn) throws ObjectStoreException
+    {
+        throw new ObjectStoreException("This should never be called");
+    }
+
+
+    private String ensureTypenamePrefix(String typeName)
+    {
+        if(!typeName.startsWith("/")) {
+            typeName = "/"+typeName;
+        }
+        return typeName;
+    }
+
+    /**
+     * Read the object's committed state.
+     *
+     * @param u  The object to work on.
+     * @param typeName The type of the object to work on.
+     * @return the state of the object.
+     */
+    @Override
+    public InputObjectState read_committed(Uid u, String typeName) throws ObjectStoreException
+    {
+        typeName = ensureTypenamePrefix(typeName);
+
+        return store.read_committed(u, typeName);
+    }
+
+    /**
+     * Remove the object's committed state.
+     *
+     * @param u  The object to work on.
+     * @param typeName The type of the object to work on.
+     * @return <code>true</code> if no errors occurred, <code>false</code>
+     *         otherwise.
+     */
+    @Override
+    public boolean remove_committed(Uid u, String typeName) throws ObjectStoreException
+    {
+        typeName = ensureTypenamePrefix(typeName);
+
+        return store.remove_committed(u, typeName);
+    }
+
+    /**
+     * Hide the object's state in the object store. Used by crash
+     * recovery.
+     *
+     * @param u  The object to work on.
+     * @param tn The type of the object to work on.
+     * @return <code>true</code> if no errors occurred, <code>false</code>
+     *         otherwise.
+     */
+    @Override
+    public boolean hide_state(Uid u, String tn) throws ObjectStoreException
+    {
+        throw new ObjectStoreException("This should never be called");
+    }
+
+    /**
+     * Reveal a hidden object's state.
+     *
+     * @param u  The object to work on.
+     * @param tn The type of the object to work on.
+     * @return <code>true</code> if no errors occurred, <code>false</code>
+     *         otherwise.
+     */
+    @Override
+    public boolean reveal_state(Uid u, String tn) throws ObjectStoreException
+    {
+        throw new ObjectStoreException("This should never be called");
+    }
+
+    /**
+     * Commit the object's state in the object store.
+     *
+     * @param u  The object to work on.
+     * @param tn The type of the object to work on.
+     * @return <code>true</code> if no errors occurred, <code>false</code>
+     *         otherwise.
+     */
+    @Override
+    public boolean commit_state(Uid u, String tn) throws ObjectStoreException
+    {
+        throw new ObjectStoreException("This should never be called");
+    }
+
+    /**
+     * @param u  The object to query.
+     * @param typeName The type of the object to query.
+     * @return the current state of the object's state (e.g., shadowed,
+     *         committed ...) [StateStatus]
+     */
+    @Override
+    public int currentState(Uid u, String typeName) throws ObjectStoreException
+    {
+        typeName = ensureTypenamePrefix(typeName);
+
+        if( store.contains(u, typeName)) {
+            return StateStatus.OS_COMMITTED;
+        } else {
+            return StateStatus.OS_UNKNOWN;
+        }
+    }
+
+
+    /**
+     * Write a copy of the object's uncommitted state.
+     *
+     * @param u    The object to work on.
+     * @param tn   The type of the object to work on.
+     * @param buff The state to write.
+     * @return <code>true</code> if no errors occurred, <code>false</code>
+     *         otherwise.
+     */
+    @Override
+    public boolean write_uncommitted(Uid u, String tn, OutputObjectState buff) throws ObjectStoreException
+    {
+        throw new ObjectStoreException("This should never be called");
+    }
+
+    /**
+     * Write a new copy of the object's committed state.
+     *
+     * @param u    The object to work on.
+     * @param typeName   The type of the object to work on.
+     * @param buff The state to write.
+     * @return <code>true</code> if no errors occurred, <code>false</code>
+     *         otherwise.
+     */
+    @Override
+    public boolean write_committed(Uid u, String typeName, OutputObjectState buff) throws ObjectStoreException
+    {
+        typeName = ensureTypenamePrefix(typeName);
+
+        return store.write_committed(u, typeName, buff);
+    }
+
+    @Override
+    public boolean allObjUids(String typeName, InputObjectState foundInstances) throws ObjectStoreException
+    {
+        typeName = ensureTypenamePrefix(typeName);
+
+        return allObjUids(typeName, foundInstances, StateStatus.OS_UNKNOWN);
+    }
+
+    /**
+     * Obtain all of the Uids for a specified type.
+     *
+     * @param typeName    The type to scan for.
+     * @param foundInstances The object state in which to store the Uids
+     * @param matchState    The file type to look for (e.g., committed, shadowed). [StateStatus]
+     * @return <code>true</code> if no errors occurred, <code>false</code>
+     *         otherwise.
+     */
+    @Override
+    public boolean allObjUids(String typeName, InputObjectState foundInstances, int matchState) throws ObjectStoreException
+    {
+        boolean result = true;
+
+        typeName = ensureTypenamePrefix(typeName);
+
+        Uid[] uids = store.getUidsForType(typeName);
+
+        OutputObjectState buffer = new OutputObjectState();
+
+        try
+        {
+            if(uids != null && (matchState == StateStatus.OS_UNKNOWN || matchState == StateStatus.OS_COMMITTED))
+            {
+                for (Uid uid: uids)
+                {
+                    UidHelper.packInto(uid, buffer);
+                }
+            }
+            UidHelper.packInto(Uid.nullUid(), buffer);
+        }
+        catch (IOException e)
+        {
+            throw new ObjectStoreException("TODO");
+        }
+
+        foundInstances.setBuffer(buffer.buffer());
+
+        return result;
+    }
+
+
+    /**
+     * Obtain all types of objects stored in the object store.
+     *
+     * @param foundTypes The state in which to store the types.
+     * @return <code>true</code> if no errors occurred, <code>false</code>
+     *         otherwise.
+     */
+    @Override
+    public boolean allTypes(InputObjectState foundTypes) throws ObjectStoreException
+    {
+        boolean result = true;
+
+        String[] knownTypes = store.getKnownTypes();
+        Set<String> typeSet = new HashSet<String>();
+
+        if (knownTypes == null || knownTypes.length == 0)
+            return true;
+
+        OutputObjectState buffer = new OutputObjectState();
+
+        try
+        {
+            for (String typeName: knownTypes)
+            {
+                if(typeName.startsWith("/")) {
+                    typeName = typeName.substring(1);
+                }
+
+                if(typeName.contains("/")) {
+                    String value = "";
+                    String[] parents = typeName.split("/");
+                    for(String parent : parents) {
+                        if(parent.length() == 0) {
+                            continue;
+                        }
+                        if(value.length() > 0) {
+                            value = value+"/";
+                        }
+                        value = value+parent;
+                        if(!typeSet.contains(value)) {
+                            typeSet.add(value);
+                            buffer.packString(value);
+                        }
+                    }
+                } else {
+                    buffer.packString(typeName);
+                }
+            }
+            buffer.packString("");
+        }
+        catch (IOException e)
+        {
+            throw new ObjectStoreException(e);
+        }
+
+        foundTypes.setBuffer(buffer.buffer());
+
+        return result;
+    }
+
+    /**
+     * Some object store implementations may be running with automatic
+     * sync disabled. Calling this method will ensure that any states are
+     * flushed to disk.
+     */
+    @Override
+    public void sync() throws SyncFailedException, ObjectStoreException
+    {
+        // null-op in this impl.
+    }
+
+    /**
+     * @return the "name" of the object store. Where in the hierarchy it appears, e.g., /ObjectStore/MyName/...
+     */
+    @Override
+    public String getStoreName()
+    {
+        return store.getStoreName();
+    }
+
+    @Override
+    public boolean fullCommitNeeded()
+    {
+        return false;
+    }
+
+    /**
+     * Is the current state of the object the same as that provided as the last
+     * parameter?
+     *
+     * @param u  The object to work on.
+     * @param tn The type of the object.
+     * @param st The expected type of the object. [StateType]
+     * @return <code>true</code> if the current state is as expected,
+     *         <code>false</code> otherwise.
+     */
+    @Override
+    public boolean isType(Uid u, String tn, int st) throws ObjectStoreException
+    {
+        return false;
+    }
+}
\ No newline at end of file



More information about the jboss-svn-commits mailing list