From 482c0c75a53ecb21325adde950438f879baf0e50 Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Tue, 31 Oct 2006 06:47:36 +0000 Subject: Index records no longer use join property to link to master and instead copy key property values. This allows IndexedRepository to properly load master records from the master storage. --- .../carbonado/repo/indexed/IndexEntryAccessor.java | 11 +- .../repo/indexed/IndexEntryGenerator.java | 15 +- .../carbonado/repo/indexed/IndexedCursor.java | 27 ++- .../carbonado/repo/indexed/ManagedIndex.java | 14 +- .../SyntheticStorableReferenceBuilder.java | 246 ++++++++------------- 5 files changed, 127 insertions(+), 186 deletions(-) diff --git a/src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryAccessor.java b/src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryAccessor.java index 16a980d..b107a6e 100644 --- a/src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryAccessor.java +++ b/src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryAccessor.java @@ -40,12 +40,13 @@ public interface IndexEntryAccessor extends IndexInfo { Storage getIndexEntryStorage(); /** - * Loads the master object referenced by the given index entry. + * Sets all the primary key properties of the given master, using the + * applicable properties of the given index entry. * - * @param indexEntry index entry which points to master - * @return master or null if missing + * @param indexEntry source of property values + * @param master master whose primary key properties will be set */ - S loadMaster(Storable indexEntry) throws FetchException; + void copyToMasterPrimaryKey(Storable indexEntry, S master); /** * Sets all the properties of the given index entry, using the applicable @@ -54,7 +55,7 @@ public interface IndexEntryAccessor extends IndexInfo { * @param indexEntry index entry whose properties will be set * @param master source of property values */ - void setAllProperties(Storable indexEntry, S master); + void copyFromMaster(Storable indexEntry, S master); /** * Returns true if the properties of the given index entry match those diff --git a/src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryGenerator.java b/src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryGenerator.java index 3da1a5b..4059ac3 100644 --- a/src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryGenerator.java +++ b/src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryGenerator.java @@ -132,13 +132,14 @@ class IndexEntryGenerator { } /** - * Loads the master object referenced by the given index entry. + * Sets all the primary key properties of the given master, using the + * applicable properties of the given index entry. * - * @param indexEntry index entry which points to master - * @return master or null if missing + * @param indexEntry source of property values + * @param master master whose primary key properties will be set */ - public S loadMaster(Storable ref) throws FetchException { - return mBuilder.loadMaster(ref); + public void copyToMasterPrimaryKey(Storable indexEntry, S master) { + mBuilder.copyToMasterPrimaryKey(indexEntry, master); } /** @@ -148,8 +149,8 @@ class IndexEntryGenerator { * @param indexEntry index entry whose properties will be set * @param master source of property values */ - public void setAllProperties(Storable indexEntry, S master) { - mBuilder.setAllProperties(indexEntry, master); + public void copyFromMaster(Storable indexEntry, S master) { + mBuilder.copyFromMaster(indexEntry, master); } /** diff --git a/src/main/java/com/amazon/carbonado/repo/indexed/IndexedCursor.java b/src/main/java/com/amazon/carbonado/repo/indexed/IndexedCursor.java index 3a50a84..892af49 100644 --- a/src/main/java/com/amazon/carbonado/repo/indexed/IndexedCursor.java +++ b/src/main/java/com/amazon/carbonado/repo/indexed/IndexedCursor.java @@ -65,8 +65,11 @@ class IndexedCursor extends AbstractCursor { } while (mCursor.hasNext()) { final Storable indexEntry = mCursor.next(); - S master = mGenerator.loadMaster(indexEntry); - if (master == null) { + + S master = mStorage.mMasterStorage.prepare(); + mGenerator.copyToMasterPrimaryKey(indexEntry, master); + + if (!master.tryLoad()) { LogFactory.getLog(getClass()).warn ("Master is missing for index entry: " + indexEntry); } else { @@ -83,7 +86,7 @@ class IndexedCursor extends AbstractCursor { final Storage indexEntryStorage = repo.getIndexEntryStorageFor(mGenerator.getIndexEntryClass()); Storable newIndexEntry = indexEntryStorage.prepare(); - mGenerator.setAllProperties(newIndexEntry, master); + mGenerator.copyFromMaster(newIndexEntry, master); if (newIndexEntry.tryLoad()) { // Good, the correct index entry exists. We'll see @@ -103,18 +106,18 @@ class IndexedCursor extends AbstractCursor { Transaction txn = repo.enterTransaction(); try { // Reload master and verify inconsistency. - S master = mGenerator.loadMaster(indexEntry); - if (mGenerator.isConsistent(indexEntry, master)) { - return; - } + S master = mStorage.mMasterStorage.prepare(); + mGenerator.copyToMasterPrimaryKey(indexEntry, master); - Storable newIndexEntry = indexEntryStorage.prepare(); - mGenerator.setAllProperties(newIndexEntry, master); + if (master.tryLoad()) { + Storable newIndexEntry = indexEntryStorage.prepare(); + mGenerator.copyFromMaster(newIndexEntry, master); - newIndexEntry.tryInsert(); + newIndexEntry.tryInsert(); - indexEntry.tryDelete(); - txn.commit(); + indexEntry.tryDelete(); + txn.commit(); + } } catch (FetchException fe) { LogFactory.getLog(IndexedCursor.class).warn ("Unable to check if repair required for " + diff --git a/src/main/java/com/amazon/carbonado/repo/indexed/ManagedIndex.java b/src/main/java/com/amazon/carbonado/repo/indexed/ManagedIndex.java index cfc399b..80ad172 100644 --- a/src/main/java/com/amazon/carbonado/repo/indexed/ManagedIndex.java +++ b/src/main/java/com/amazon/carbonado/repo/indexed/ManagedIndex.java @@ -126,13 +126,13 @@ class ManagedIndex implements IndexEntryAccessor { } // Required by IndexEntryAccessor interface. - public S loadMaster(Storable indexEntry) throws FetchException { - return mGenerator.loadMaster(indexEntry); + public void copyToMasterPrimaryKey(Storable indexEntry, S master) { + mGenerator.copyToMasterPrimaryKey(indexEntry, master); } // Required by IndexEntryAccessor interface. - public void setAllProperties(Storable indexEntry, S master) { - mGenerator.setAllProperties(indexEntry, master); + public void copyFromMaster(Storable indexEntry, S master) { + mGenerator.copyFromMaster(indexEntry, master); } // Required by IndexEntryAccessor interface. @@ -388,7 +388,7 @@ class ManagedIndex implements IndexEntryAccessor { private Storable makeIndexEntry(S userStorable) { Storable indexEntry = mIndexEntryStorage.prepare(); - mGenerator.setAllProperties(indexEntry, userStorable); + mGenerator.copyFromMaster(indexEntry, userStorable); return indexEntry; } @@ -403,7 +403,7 @@ class ManagedIndex implements IndexEntryAccessor { // If index entry already exists, then index might be corrupt. { Storable freshEntry = mIndexEntryStorage.prepare(); - mGenerator.setAllProperties(freshEntry, userStorable); + mGenerator.copyFromMaster(freshEntry, userStorable); indexEntry.copyVersionProperty(freshEntry); if (freshEntry.equals(indexEntry)) { // Existing entry is exactly what we expect. Return false @@ -433,7 +433,7 @@ class ManagedIndex implements IndexEntryAccessor { } Storable freshEntry = mIndexEntryStorage.prepare(); - mGenerator.setAllProperties(freshEntry, freshUserStorable); + mGenerator.copyFromMaster(freshEntry, freshUserStorable); // Blow it away entry and re-insert. Don't simply update // the entry, since record version number may prevent diff --git a/src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceBuilder.java b/src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceBuilder.java index 443d826..78bf22e 100644 --- a/src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceBuilder.java +++ b/src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceBuilder.java @@ -29,8 +29,6 @@ import java.util.Map; import java.util.Set; import com.amazon.carbonado.FetchException; -import com.amazon.carbonado.Join; -import com.amazon.carbonado.Nullable; import com.amazon.carbonado.Storable; import com.amazon.carbonado.SupportException; import com.amazon.carbonado.info.Direction; @@ -73,10 +71,10 @@ import org.cojen.util.BeanComparator; public class SyntheticStorableReferenceBuilder implements SyntheticBuilder { - // The property setter will be called something like "setAllProperties_0" - private static final String ALL_PROPERTIES_PREFIX = "setAllProperties_"; + // The property setter will be called something like "copyFromMaster_0" + private static final String COPY_FROM_MASTER_PREFIX = "copyFromMaster_"; - private static final String MASTER_PROPERTY_PREFIX = "master_"; + private static final String COPY_TO_MASTER_PK_PREFIX = "copyToMasterPk_"; private static final String IS_CONSISTENT_PREFIX = "getIsConsistent_"; @@ -112,23 +110,14 @@ public class SyntheticStorableReferenceBuilder // are retrieved from the master. private List mCommonProps; - // The builder generates and retains a reference to various - // methods which make it possible to implement the "StorableReferenceBean" - // interface - // (if there were any need to formalize it): loadMaster, - // copyCommonProperties, - // setAllProperties, and isConsistent - private String mNameForSetAllPropertiesMethod; - - private Method mSetAllPropertiesMethod; - - private String mNameForIsConsistentMethod; + private String mCopyFromMasterMethodName; + private Method mCopyFromMasterMethod; + private String mIsConsistentMethodName; private Method mIsConsistentMethod; - private String mNameForGetMasterMethod; - - private Method mGetMasterMethod; + private String mCopyToMasterPkMethodName; + private Method mCopyToMasterPkMethod; private Comparator mComparator; @@ -227,7 +216,7 @@ public class SyntheticStorableReferenceBuilder * @see com.amazon.carbonado.synthetic.SyntheticBuilder#getStorableClass() */ public Class getStorableClass() throws IllegalStateException { - if (null == mSyntheticClass) { + if (mSyntheticClass == null) { mSyntheticClass = mBuilder.getStorableClass(); // We need a comparator which follows the same order as the generated @@ -265,7 +254,7 @@ public class SyntheticStorableReferenceBuilder */ public SyntheticProperty addKeyProperty(String name, Direction direction) { StorableProperty prop = mMasterStorableInfo.getAllProperties().get(name); - if (null == prop) { + if (prop == null) { throw new IllegalArgumentException(name + " is not a property of " + mMasterStorableInfo.getName()); } @@ -355,28 +344,26 @@ public class SyntheticStorableReferenceBuilder } /** - * Loads the master object referenced by the given index entry. + * Sets all the primary key properties of the given master, using the + * applicable properties of the given index entry. * - * @param indexEntry - * index entry which points to master - * @return master or null if missing + * @param indexEntry source of property values + * @param master master whose primary key properties will be set */ - public S loadMaster(Storable indexEntry) throws FetchException { - if (null == mGetMasterMethod) { + public void copyToMasterPrimaryKey(Storable indexEntry, S master) { + if (mCopyToMasterPkMethod == null) { try { - mGetMasterMethod = getStorableClass().getMethod(mNameForGetMasterMethod, - (Class[]) null); + mCopyToMasterPkMethod = + mSyntheticClass.getMethod(mCopyToMasterPkMethodName, mMasterStorableClass); } catch (NoSuchMethodException e) { throw new UndeclaredThrowableException(e); } } try { - return (S) mGetMasterMethod.invoke(indexEntry, (Object[]) null); + mCopyToMasterPkMethod.invoke(indexEntry, master); } catch (Exception e) { - ThrowUnchecked.fireFirstDeclaredCause(e, FetchException.class); - // Not reached. - return null; + ThrowUnchecked.fireFirstDeclaredCause(e); } } @@ -384,24 +371,21 @@ public class SyntheticStorableReferenceBuilder * Sets all the properties of the given index entry, using the applicable * properties of the given master. * - * @param indexEntry - * index entry whose properties will be set - * @param master - * source of property values + * @param indexEntry index entry whose properties will be set + * @param master source of property values */ - public void setAllProperties(Storable indexEntry, S master) { - - if (null == mSetAllPropertiesMethod) { + public void copyFromMaster(Storable indexEntry, S master) { + if (mCopyFromMasterMethod == null) { try { - mSetAllPropertiesMethod = mSyntheticClass.getMethod(mNameForSetAllPropertiesMethod, - mMasterStorableClass); + mCopyFromMasterMethod = + mSyntheticClass.getMethod(mCopyFromMasterMethodName, mMasterStorableClass); } catch (NoSuchMethodException e) { throw new UndeclaredThrowableException(e); } } try { - mSetAllPropertiesMethod.invoke(indexEntry, master); + mCopyFromMasterMethod.invoke(indexEntry, master); } catch (Exception e) { ThrowUnchecked.fireFirstDeclaredCause(e); } @@ -410,7 +394,7 @@ public class SyntheticStorableReferenceBuilder /** * Returns true if the properties of the given index entry match those * contained in the master, excluding any version property. This will - * always return true after a call to setAllProperties. + * always return true after a call to copyFromMaster. * * @param indexEntry * index entry whose properties will be tested @@ -418,11 +402,10 @@ public class SyntheticStorableReferenceBuilder * source of property values */ public boolean isConsistent(Storable indexEntry, S master) { - - if (null == mIsConsistentMethod) { + if (mIsConsistentMethod == null) { try { - mIsConsistentMethod = mSyntheticClass.getMethod(mNameForIsConsistentMethod, - mMasterStorableClass); + mIsConsistentMethod = + mSyntheticClass.getMethod(mIsConsistentMethodName, mMasterStorableClass); } catch (NoSuchMethodException e) { throw new UndeclaredThrowableException(e); } @@ -445,96 +428,35 @@ public class SyntheticStorableReferenceBuilder } /** - * Create methods for copying properties to and from and for looking up the - * master object + * Create methods for copying properties and testing properties. * * @throws amazon.carbonado.SupportException */ private void addSpecialMethods(ClassFile cf) throws SupportException { - TypeDesc masterStorableType = TypeDesc.forClass(mMasterStorableClass); - // The set master method is used to load the master object and set it - // into the master property of this reference storable - String nameForSetMasterMethod; - // Generate safe names for special methods. { - String safeName = generateSafePropertyName(mMasterStorableInfo, - MASTER_PROPERTY_PREFIX); - // Don't need to pass the class in, it's not a boolean so we'll get - // a "get" flavor read method - mNameForGetMasterMethod = SyntheticProperty.makeReadMethodName(safeName, - Object.class); - nameForSetMasterMethod = SyntheticProperty.makeWriteMethodName(safeName); - mNameForSetAllPropertiesMethod = generateSafeMethodName(mMasterStorableInfo, - ALL_PROPERTIES_PREFIX); - mNameForIsConsistentMethod = generateSafeMethodName(mMasterStorableInfo, IS_CONSISTENT_PREFIX); - } + mCopyToMasterPkMethodName = + generateSafeMethodName(mMasterStorableInfo, COPY_TO_MASTER_PK_PREFIX); - // Add a method which sets all properties of index entry object from - // master object. - { - // void setAllProperties(Storable master) - TypeDesc[] params = new TypeDesc[] { masterStorableType }; - MethodInfo mi = cf.addMethod(Modifiers.PUBLIC, - mNameForSetAllPropertiesMethod, - null, - params); - CodeBuilder b = new CodeBuilder(mi); + mCopyFromMasterMethodName = + generateSafeMethodName(mMasterStorableInfo, COPY_FROM_MASTER_PREFIX); - // Set Join property: this.setMaster(master) - // (stash a reference to the master object) - b.loadThis(); - b.loadLocal(b.getParameter(0)); - b.invokeVirtual(nameForSetMasterMethod, null, params); - - // Copy across all the properties. At this point they've - // all been added to the property list - for (StorableProperty prop : mCommonProps) { - if (prop.isPrimaryKeyMember()) { - // No need to set this property, since setting join to - // master already took care of it. - continue; - } - b.loadThis(); - b.loadLocal(b.getParameter(0)); - if (prop.getReadMethod() == null) { - throw new SupportException("Property does not have a public accessor method: " - + prop); - } - b.invoke(prop.getReadMethod()); - b.invokeVirtual(prop.getWriteMethodName(), - null, - new TypeDesc[] { TypeDesc.forClass(prop.getType()) }); - - } - b.returnVoid(); + mIsConsistentMethodName = + generateSafeMethodName(mMasterStorableInfo, IS_CONSISTENT_PREFIX); } - // Add a join property for looking up master object. Since binding is - // based on primary key properties which match to index entry object, - // the join is natural -- no need to specify internal and external - // properties. - { - MethodInfo mi = cf.addMethod(Modifiers.PUBLIC_ABSTRACT, - mNameForGetMasterMethod, - masterStorableType, - null); - mi.addException(TypeDesc.forClass(FetchException.class)); - mi.addRuntimeVisibleAnnotation(TypeDesc.forClass(Join.class)); - mi.addRuntimeVisibleAnnotation(TypeDesc.forClass(Nullable.class)); - - cf.addMethod(Modifiers.PUBLIC_ABSTRACT, - nameForSetMasterMethod, - null, - new TypeDesc[] { masterStorableType }); - } + // Add methods which copies properties between master and index entry. + addCopyMethod(cf, mCopyFromMasterMethodName); + addCopyMethod(cf, mCopyToMasterPkMethodName); + + TypeDesc masterStorableType = TypeDesc.forClass(mMasterStorableClass); // Add a method which tests all properties of index entry object // against master object, excluding the version property. { TypeDesc[] params = new TypeDesc[] {masterStorableType}; MethodInfo mi = cf.addMethod - (Modifiers.PUBLIC, mNameForIsConsistentMethod, TypeDesc.BOOLEAN, params); + (Modifiers.PUBLIC, mIsConsistentMethodName, TypeDesc.BOOLEAN, params); CodeBuilder b = new CodeBuilder(mi); for (StorableProperty prop : mCommonProps) { @@ -549,9 +471,56 @@ public class SyntheticStorableReferenceBuilder b.loadConstant(true); b.returnValue(TypeDesc.BOOLEAN); } + } + private void addCopyMethod(ClassFile cf, String methodName) throws SupportException { + TypeDesc masterStorableType = TypeDesc.forClass(mMasterStorableClass); + // void copyXxMaster(Storable master) + TypeDesc[] params = new TypeDesc[] { masterStorableType }; + MethodInfo mi = cf.addMethod(Modifiers.PUBLIC, methodName, null, params); + CodeBuilder b = new CodeBuilder(mi); + + boolean toMasterPk; + if (methodName.equals(mCopyToMasterPkMethodName)) { + toMasterPk = true; + } else if (methodName.equals(mCopyFromMasterMethodName)) { + toMasterPk = false; + } else { + throw new IllegalArgumentException(); + } + for (StorableProperty prop : mCommonProps) { + if (toMasterPk && !prop.isPrimaryKeyMember()) { + continue; + } + + if (prop.getReadMethod() == null) { + throw new SupportException + ("Property does not have a public accessor method: " + prop); + } + if (prop.getWriteMethod() == null) { + throw new SupportException + ("Property does not have a public mutator method: " + prop); + } + + TypeDesc propType = TypeDesc.forClass(prop.getType()); + + if (toMasterPk) { + b.loadLocal(b.getParameter(0)); + b.loadThis(); + b.invokeVirtual(prop.getReadMethodName(), propType, null); + b.invoke(prop.getWriteMethod()); + } else if (methodName.equals(mCopyFromMasterMethodName)) { + b.loadThis(); + b.loadLocal(b.getParameter(0)); + b.invoke(prop.getReadMethod()); + b.invokeVirtual(prop.getWriteMethodName(), null, new TypeDesc[] {propType}); + } + + } + + b.returnVoid(); } /** @@ -589,10 +558,6 @@ public class SyntheticStorableReferenceBuilder private String generateSafeMethodName(StorableInfo info, String prefix) { Class type = info.getStorableType(); -// if (!methodExists(type, prefix)) { -// return prefix; -// } - // Try a few times to generate a unique name. There's nothing special // about choosing 100 as the limit. int value = 0; @@ -608,35 +573,6 @@ public class SyntheticStorableReferenceBuilder + prefix); } - /** - * Generates a property name which doesn't clash with any already defined. - */ - protected String generateSafePropertyName(StorableInfo info, String prefix) - { - Map properties = info.getAllProperties(); - Class type = info.getStorableType(); - - // Try a few times to generate unique name. There's nothing special - // about choosing 100 as the limit. - for (int i = 0; i < 100; i++) { - String name = prefix + i; - if (properties.containsKey(name)) { - continue; - } - if (methodExists(type, SyntheticProperty.makeReadMethodName(name, - type))) { - continue; - } - if (methodExists(type, SyntheticProperty.makeWriteMethodName(name))) { - continue; - } - return name; - } - - throw new InternalError("Unable to create unique property name starting with: " - + prefix); - } - /** * Look for conflicting method names */ -- cgit v1.2.3