diff src/org/dancres/blitz/oid/FIFOAllocatorImpl.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/dancres/blitz/oid/FIFOAllocatorImpl.java	Sat Mar 21 11:00:06 2009 +0000
@@ -0,0 +1,172 @@
+package org.dancres.blitz.oid;
+
+import java.io.Serializable;
+import java.io.IOException;
+
+import java.util.Random;
+import java.util.ArrayList;
+
+import java.util.logging.*;
+
+import org.dancres.blitz.disk.DiskTxn;
+import org.dancres.blitz.disk.Disk;
+import org.dancres.blitz.disk.Syncable;
+
+import org.dancres.blitz.meta.Registry;
+import org.dancres.blitz.meta.RegistryAccessor;
+import org.dancres.blitz.meta.RegistryFactory;
+import org.dancres.blitz.meta.MetaIterator;
+import org.dancres.blitz.meta.MetaEntry;
+import org.dancres.blitz.meta.Initializer;
+
+import org.dancres.blitz.Logging;
+import org.dancres.blitz.BootContext;
+
+import org.dancres.blitz.txn.UnsyncdOps;
+
+/**
+   <p>Provides an OID allocation service using a single zone at a time.
+   The early OID's are smaller numerically than later OID's such that the
+   user of these OID's can apply an ordering which yields FIFO behaviour.</p>
+ */
+class FIFOAllocatorImpl implements AllocatorAdmin, Syncable {
+    static Logger theLogger =
+        Logging.newLogger("org.dancres.blitz.oid.Allocator");
+
+    private static final byte[] ALLOCATOR_KEY =
+        new byte[] {0x00, 0x00, 0x00, 0x01};
+
+    private static int MAX_ALLOCATOR = 512;
+
+    private OIDAllocator theAllocator;
+
+    private Registry theMetaData;
+    private String theName;
+
+    FIFOAllocatorImpl(String aName) throws IOException {
+        theLogger.log(Level.INFO, "FIFOAllocator: " + aName);
+
+        theMetaData =
+            RegistryFactory.get(getDbNameFor(aName),
+                                new OIDInitializer());
+        theName = aName;
+
+        UnsyncdOps myBarrier = (UnsyncdOps)
+            BootContext.get(UnsyncdOps.class);
+
+        if (myBarrier != null) {
+            theLogger.log(Level.INFO, theName + ":Resync'ing allocator: " +
+                               myBarrier.getOpsSinceLastCheckpoint());
+        }
+
+        loadAllocator();
+
+        if (myBarrier != null) {
+            theAllocator.jump(myBarrier.getOpsSinceLastCheckpoint());
+
+            if (theAllocator.isExhausted()) {
+                if (theAllocator.getId() == (MAX_ALLOCATOR - 1))
+                    throw new Error("FIFOAllocator was exhausted - VERY BAD!");
+
+                theAllocator = new OIDAllocator(theAllocator.getId() + 1,
+                                                theAllocator.getId() + 1);
+                theAllocator.jump(myBarrier.getOpsSinceLastCheckpoint());
+            }
+
+            try {
+                sync();
+            } catch (Exception anE) {
+                theLogger.log(Level.SEVERE, theName +
+                              ":Failed to sync against barrier",
+                              anE);
+                throw new IOException("Failed to sync against barrier");
+            }
+        }
+
+        Disk.add(this);
+    }
+
+    private void loadAllocator() throws IOException  {
+        DiskTxn myStandalone = DiskTxn.newStandalone();
+
+        MetaIterator myAllocatorStates =
+            theMetaData.getAccessor(myStandalone).readAll();
+
+        Serializable myEntry =
+            theMetaData.getAccessor(myStandalone).load(ALLOCATOR_KEY);
+
+        OIDAllocator myAllocator = new OIDAllocator();
+        myAllocator.setState(myEntry);
+
+        theAllocator = myAllocator;
+        myStandalone.commit();
+    }
+
+    /**
+       Call this within an active DiskTxn
+     */
+    public OID getNextId() throws IOException {
+        synchronized(this) {
+
+            OID myID = null;
+
+            if (theAllocator.isExhausted()) {
+                if (theAllocator.getId() == (MAX_ALLOCATOR - 1))
+                    throw new Error("FIFOAllocator was exhausted - VERY BAD!");
+
+                theAllocator = new OIDAllocator(theAllocator.getId() + 1,
+                                                theAllocator.getId() + 1);
+            }
+
+            myID = theAllocator.newOID();
+
+            return myID;
+        }
+    }
+
+    public int getMaxZoneId() {
+        /*
+          HACK:  We put up an arbitary limit, if we ever exceed this
+          we'll break LeaseTrackerImpl in blitz.entry
+         */
+        return MAX_ALLOCATOR;
+    }
+
+    public void sync() throws Exception {
+        DiskTxn myTxn = DiskTxn.newStandalone();
+
+        RegistryAccessor myAccessor = theMetaData.getAccessor(myTxn);
+
+        synchronized(this) {
+            myAccessor.save(ALLOCATOR_KEY, theAllocator.getState());
+        }
+
+        myTxn.commit(true);
+    }
+
+    public void close() throws Exception {
+        theMetaData.close();
+    }
+
+    public void delete() throws IOException {
+        theMetaData.close();
+
+        RegistryFactory.delete(getDbNameFor(theName));
+
+        Disk.remove(this);
+    }
+
+    private String getDbNameFor(String aName) {
+        return aName + "_oid";
+    }
+
+    private class OIDInitializer implements Initializer {
+        OIDInitializer() {
+        }
+
+        public void execute(RegistryAccessor anAccessor) throws IOException {
+            OIDAllocator myAlloc = new OIDAllocator(0);
+            anAccessor.save(ALLOCATOR_KEY, myAlloc.getState());
+        }
+    }
+}