From 79d893ac1bad62d94750b26980f45928330870ed Mon Sep 17 00:00:00 2001
From: "Brian S. O'Neill" <bronee@gmail.com>
Date: Tue, 6 Nov 2012 00:19:54 +0000
Subject: Layout metadata sync fixes.

---
 .../java/com/amazon/carbonado/layout/Layout.java   | 50 ++++++++++++++-------
 .../com/amazon/carbonado/layout/LayoutFactory.java | 51 +++++++++++++++++++---
 .../com/amazon/carbonado/layout/LayoutSync.java    | 27 +++---------
 3 files changed, 84 insertions(+), 44 deletions(-)

(limited to 'src/main/java/com/amazon/carbonado/layout')

diff --git a/src/main/java/com/amazon/carbonado/layout/Layout.java b/src/main/java/com/amazon/carbonado/layout/Layout.java
index 89806fe..d11e4ef 100644
--- a/src/main/java/com/amazon/carbonado/layout/Layout.java
+++ b/src/main/java/com/amazon/carbonado/layout/Layout.java
@@ -41,6 +41,7 @@ import com.amazon.carbonado.FetchException;
 import com.amazon.carbonado.FetchNoneException;
 import com.amazon.carbonado.PersistException;
 import com.amazon.carbonado.Query;
+import com.amazon.carbonado.Repository;
 import com.amazon.carbonado.RepositoryException;
 import com.amazon.carbonado.Storable;
 import com.amazon.carbonado.Storage;
@@ -343,30 +344,38 @@ public class Layout {
     {
         final String filter = "storableTypeName = ? & generation = ?";
 
-        final FetchNoneException ex;
         try {
-            return mLayoutFactory.mLayoutStorage
+            StoredLayoutEquivalence equiv =
+                mLayoutFactory.mRepository.storageFor(StoredLayoutEquivalence.class)
                 .query(filter)
                 .with(getStorableTypeName()).with(generation)
-                .loadOne();
-        } catch (FetchNoneException e) {
-            ex = e;
+                .tryLoadOne();
+            if (equiv != null) {
+                generation = equiv.getMatchedGeneration();
+            }
+        } catch (RepositoryException e) {
+            throw e.toFetchException();
         }
 
-        // Index might be inconsistent.
-        Cursor<StoredLayout> c = 
-            FilteredCursor.applyFilter(mLayoutFactory.mLayoutStorage.query().fetch(),
-                                       StoredLayout.class, filter,
-                                       getStorableTypeName(), generation);
-
         try {
-            if (c.hasNext()) {
-                return c.next();
+            Cursor<StoredLayout> c = findLayouts
+                (mLayoutFactory.mRepository, getStorableTypeName(), generation);
+
+            try {
+                if (c.hasNext()) {
+                    return c.next();
+                }
+            } finally {
+                c.close();
             }
-        } finally {
-            c.close();
+        } catch (RepositoryException e) {
+            throw e.toFetchException();
         }
 
+        FetchException ex = new FetchNoneException
+            ("Layout generation not found: " + getStorableTypeName() + ", " + generation);
+
+
         // Try to resync with a master.
         ResyncCapability cap =
             mLayoutFactory.mRepository.getCapability(ResyncCapability.class);
@@ -400,6 +409,17 @@ public class Layout {
         return storedLayout;
     }
 
+    static Cursor<StoredLayout> findLayouts(Repository repo,
+                                            String storableTypeName, int generation)
+        throws RepositoryException
+    {
+        // Query without using the index, in case it's inconsistent.
+        return FilteredCursor.applyFilter
+            (repo.storageFor(StoredLayout.class).query().fetch(),
+             StoredLayout.class, "storableTypeName = ? & generation = ?",
+             storableTypeName, generation);
+    }
+
     /**
      * Returns the previous known generation of the storable's layout, or null
      * if none.
diff --git a/src/main/java/com/amazon/carbonado/layout/LayoutFactory.java b/src/main/java/com/amazon/carbonado/layout/LayoutFactory.java
index 5a29152..c4333da 100644
--- a/src/main/java/com/amazon/carbonado/layout/LayoutFactory.java
+++ b/src/main/java/com/amazon/carbonado/layout/LayoutFactory.java
@@ -269,7 +269,7 @@ public class LayoutFactory implements LayoutCapability {
                     // exception, which prevents the mistake from persisting.
 
                     assert(newLayout != null);
-                    int generation = nextGeneration(info.getStorableType().getName());
+                    int generation = nextGeneration(mRepository, info.getStorableType().getName());
 
                     newLayout.insert(readOnly, generation);
                     layout = newLayout;
@@ -372,7 +372,7 @@ public class LayoutFactory implements LayoutCapability {
                 } else {
                     // Assume alternate key constraint, so increment the generation.
                     storedLayout.setGeneration
-                        (nextGeneration(storedLayout.getStorableTypeName()));
+                        (nextGeneration(mRepository, storedLayout.getStorableTypeName()));
                     storedLayout.insert();
                 }
             }
@@ -413,19 +413,56 @@ public class LayoutFactory implements LayoutCapability {
         mReconstructed.put(reconstructed, layout);
     }
 
-    private int nextGeneration(String typeName) throws FetchException {
-        Cursor<StoredLayout> cursor = mLayoutStorage
-            .query("storableTypeName = ?").with(typeName).orderBy("-generation").fetch();
+    static int nextGeneration(Repository repo, String typeName) throws FetchException {
+        int highestGen = -1;
+        {
+            Cursor<StoredLayout> cursor;
+            try {
+                cursor = repo.storageFor(StoredLayout.class).query("storableTypeName = ?")
+                    .with(typeName).orderBy("-generation").fetchSlice(0, 1L);
+            } catch (RepositoryException e) {
+                throw e.toFetchException();
+            }
+
+            try {
+                if (cursor.hasNext()) {
+                    highestGen = cursor.next().getGeneration();
+                }
+            } finally {
+                cursor.close();
+            }
+        }
+
+        Storage<StoredLayoutEquivalence> es;
+        try {
+            es = repo.storageFor(StoredLayoutEquivalence.class);
+        } catch (RepositoryException e) {
+            throw e.toFetchException();
+        }
+
+        Cursor<StoredLayoutEquivalence> cursor = es.query("storableTypeName = ?")
+            .with(typeName).orderBy("-generation").fetchSlice(0, 1L);
+
+        try {
+            if (cursor.hasNext()) {
+                highestGen = Math.max(highestGen, cursor.next().getGeneration());
+            }
+        } finally {
+            cursor.close();
+        }
+
+        cursor = es.query("storableTypeName = ?")
+            .with(typeName).orderBy("-matchedGeneration").fetchSlice(0, 1L);
 
         try {
             if (cursor.hasNext()) {
-                return cursor.next().getGeneration() + 1;
+                highestGen = Math.max(highestGen, cursor.next().getMatchedGeneration());
             }
         } finally {
             cursor.close();
         }
 
-        return 0;
+        return highestGen + 1;
     }
 
     /**
diff --git a/src/main/java/com/amazon/carbonado/layout/LayoutSync.java b/src/main/java/com/amazon/carbonado/layout/LayoutSync.java
index 510dc82..cf311e0 100644
--- a/src/main/java/com/amazon/carbonado/layout/LayoutSync.java
+++ b/src/main/java/com/amazon/carbonado/layout/LayoutSync.java
@@ -178,6 +178,7 @@ public class LayoutSync {
 
         String storableTypeName = src.getStorableTypeName();
         if (!storableTypeName.equals(dst.getStorableTypeName())) {
+            // Assume that there's never any hashcode collision.
             throw new AssertionError();
         }
 
@@ -267,31 +268,13 @@ public class LayoutSync {
     private int nextGen(Repository repo, String storableTypeName)
         throws RepositoryException
     {
-        Cursor<StoredLayout> cursor =
-            repo.storageFor(StoredLayout.class)
-            .query("storableTypeName = ?").with(storableTypeName)
-            .orderBy("-generation")
-            .fetchSlice(0, 1L);
-
-        try {
-            // Must always return a result. Otherwise, no conflict existed in
-            // the first place, indicating a bug.
-            return cursor.next().getGeneration() + 1;
-        } finally {
-            cursor.close();
-        }
-
-        // TODO: also choose from highest equivalence
+        return LayoutFactory.nextGeneration(repo, storableTypeName);
     }
 
-    private Cursor<StoredLayout> findLayouts(Repository repo,
-                                             String storableTypeName, int generation)
+    static Cursor<StoredLayout> findLayouts(Repository repo,
+                                            String storableTypeName, int generation)
         throws RepositoryException
     {
-        // Query without using the index, in case it's inconsistent.
-        return FilteredCursor.applyFilter
-            (repo.storageFor(StoredLayout.class).query().fetch(),
-             StoredLayout.class, "storableTypeName = ? & generation = ?",
-             storableTypeName, generation);
+        return Layout.findLayouts(repo, storableTypeName, generation);
     }
 }
-- 
cgit v1.2.3