diff options
author | Brian S. O'Neill <bronee@gmail.com> | 2010-03-10 01:25:48 +0000 |
---|---|---|
committer | Brian S. O'Neill <bronee@gmail.com> | 2010-03-10 01:25:48 +0000 |
commit | 1d9e9f45ffe83515b2a6da1eb6ad320d46f9ce9f (patch) | |
tree | 7a8078c0565eaa3c705150b0b92a893f1878d24a | |
parent | 1a40e5e6bbfc26020f5b7b625f162409e5209e88 (diff) |
Add master feature to check if partition key has been fully specified.
3 files changed, 243 insertions, 82 deletions
diff --git a/src/main/java/com/amazon/carbonado/gen/MasterFeature.java b/src/main/java/com/amazon/carbonado/gen/MasterFeature.java index fa0a06c..a636b9c 100644 --- a/src/main/java/com/amazon/carbonado/gen/MasterFeature.java +++ b/src/main/java/com/amazon/carbonado/gen/MasterFeature.java @@ -60,4 +60,7 @@ public enum MasterFeature { /** Ensure delete operation always is in a transaction, "for update". */
DELETE_TXN_FOR_UPDATE,
+
+ /** Enforce rules for Storables which have a partition key */
+ PARTITIONING
}
diff --git a/src/main/java/com/amazon/carbonado/gen/MasterStorableGenerator.java b/src/main/java/com/amazon/carbonado/gen/MasterStorableGenerator.java index afb1a29..1c63d0c 100644 --- a/src/main/java/com/amazon/carbonado/gen/MasterStorableGenerator.java +++ b/src/main/java/com/amazon/carbonado/gen/MasterStorableGenerator.java @@ -1,5 +1,5 @@ /*
- * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Copyright 2006-2010 Amazon Technologies, Inc. or its affiliates.
* Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
* of Amazon Technologies, Inc. or its affiliates. All rights reserved.
*
@@ -64,6 +64,7 @@ import static com.amazon.carbonado.gen.CommonMethodNames.*; * transactions since this class takes care of that.
*
* @author Brian S O'Neill
+ * @author Olga Kuznetsova
* @since 1.2
*/
public final class MasterStorableGenerator<S extends Storable> {
@@ -175,6 +176,10 @@ public final class MasterStorableGenerator<S extends Storable> { if (info.getVersionProperty() == null) {
features.remove(MasterFeature.VERSIONING);
}
+
+ if (info.getPartitionKey() == null || info.getPartitionKey().getProperties().size() == 0) {
+ features.remove(MasterFeature.PARTITIONING);
+ }
}
// Add implied features.
@@ -293,99 +298,151 @@ public final class MasterStorableGenerator<S extends Storable> { mi.addException(persistExceptionType);
}
- // Add required protected doTryInsert method.
+ // Add features pertaining to partitioning
{
- // If sequence support requested, implement special insert hook to
- // call sequences for properties which are UNINITIALIZED. User may
- // provide explicit values for properties with sequences.
+ if (mFeatures.contains(MasterFeature.PARTITIONING)) {
- if (mFeatures.contains(MasterFeature.INSERT_SEQUENCES)) {
- MethodInfo mi = mClassFile.addMethod
- (Modifiers.PROTECTED,
- StorableGenerator.CHECK_PK_FOR_INSERT_METHOD_NAME,
- null, null);
- CodeBuilder b = new CodeBuilder(mi);
-
- int ordinal = 0;
+ // Overwrite write function for each property if Partitioning is enabled to check
+ // that properties that are part of the Partition key are not overwritten when clean
for (StorableProperty<S> property : mAllProperties.values()) {
- if (!property.isDerived() && property.getSequenceName() != null) {
- // Check the state of this property, to see if it is
- // uninitialized. Uninitialized state has value zero.
-
+ if (!property.isDerived() && property.isPartitionKeyMember()) {
+ Method writeMethod = property.getWriteMethod();
+ MethodInfo mi;
+ String writeName = property.getWriteMethodName();
+ final TypeDesc type = TypeDesc.forClass(property.getType());
+ if (writeMethod != null) {
+ mi = mClassFile.addMethod(writeMethod);
+ } else {
+ continue;
+ }
+ CodeBuilder b = new CodeBuilder(mi);
String stateFieldName =
- StorableGenerator.PROPERTY_STATE_FIELD_NAME + (ordinal >> 4);
-
+ StorableGenerator.PROPERTY_STATE_FIELD_NAME + (property.getNumber() >> 4);
b.loadThis();
b.loadField(stateFieldName, TypeDesc.INT);
- int shift = (ordinal & 0xf) * 2;
- b.loadConstant(StorableGenerator.PROPERTY_STATE_MASK << shift);
+ b.loadConstant(StorableGenerator.PROPERTY_STATE_MASK << ((property.getNumber() & 0xf) * 2));
b.math(Opcode.IAND);
-
- Label isInitialized = b.createLabel();
- b.ifZeroComparisonBranch(isInitialized, "!=");
-
- // Load this in preparation for storing value to property.
+ b.loadConstant(StorableGenerator.PROPERTY_STATE_CLEAN << ((property.getNumber() & 0xf) * 2));
+ Label isMutable = b.createLabel();
+ b.ifComparisonBranch(isMutable, "!=");
+ CodeBuilderUtil.throwException
+ (b, IllegalStateException.class, "Cannot alter partition key");
+ isMutable.setLocation();
b.loadThis();
+ b.loadLocal(b.getParameter(0));
+ b.invokeSuper(mClassFile.getSuperClassName(),
+ writeName,
+ null, new TypeDesc[]{type});
+ b.returnVoid();
+ }
+ }
+ }
+ }
+
+ // Add required protected doTryInsert method.
+ {
+ if (mFeatures.contains(MasterFeature.PARTITIONING) ||
+ mFeatures.contains(MasterFeature.INSERT_SEQUENCES)) {
- // Call MasterSupport.getSequenceValueProducer(String).
- TypeDesc seqValueProdType = TypeDesc.forClass(SequenceValueProducer.class);
- b.loadThis();
- b.loadField(StorableGenerator.SUPPORT_FIELD_NAME, triggerSupportType);
- b.checkCast(masterSupportType);
- b.loadConstant(property.getSequenceName());
- b.invokeInterface
- (masterSupportType, "getSequenceValueProducer",
- seqValueProdType, new TypeDesc[] {TypeDesc.STRING});
-
- // Find appropriate method to call for getting next sequence value.
- TypeDesc propertyType = TypeDesc.forClass(property.getType());
- TypeDesc propertyObjType = propertyType.toObjectType();
- Method method;
-
- try {
- if (propertyObjType == TypeDesc.LONG.toObjectType()) {
- method = SequenceValueProducer.class
- .getMethod("nextLongValue", (Class[]) null);
- } else if (propertyObjType == TypeDesc.INT.toObjectType()) {
- method = SequenceValueProducer.class
- .getMethod("nextIntValue", (Class[]) null);
- } else if (propertyObjType == TypeDesc.STRING) {
- method = SequenceValueProducer.class
- .getMethod("nextDecimalValue", (Class[]) null);
- } else {
- throw new SupportException
- ("Unable to support sequence of type \"" +
- TypeDesc.forClass(property.getType()).getFullName() +
- "\" for property: " + property.getName());
+ MethodInfo mi = mClassFile.addMethod
+ (Modifiers.PROTECTED,
+ StorableGenerator.CHECK_PK_FOR_INSERT_METHOD_NAME,
+ null, null);
+ CodeBuilder b = new CodeBuilder(mi);
+
+ if (mFeatures.contains(MasterFeature.PARTITIONING)) {
+ // Check that partition key exists in insert operation
+ checkIfPartitionKeyPresent(b);
+ }
+
+ // If sequence support requested, implement special insert hook to
+ // call sequences for properties which are UNINITIALIZED. User may
+ // provide explicit values for properties with sequences.
+
+ if (mFeatures.contains(MasterFeature.INSERT_SEQUENCES)) {
+
+ int ordinal = 0;
+ for (StorableProperty<S> property : mAllProperties.values()) {
+ if (!property.isDerived() && property.getSequenceName() != null) {
+ // Check the state of this property, to see if it is
+ // uninitialized. Uninitialized state has value zero.
+
+ String stateFieldName =
+ StorableGenerator.PROPERTY_STATE_FIELD_NAME + (ordinal >> 4);
+
+ b.loadThis();
+ b.loadField(stateFieldName, TypeDesc.INT);
+ int shift = (ordinal & 0xf) * 2;
+ b.loadConstant(StorableGenerator.PROPERTY_STATE_MASK << shift);
+ b.math(Opcode.IAND);
+
+ Label isInitialized = b.createLabel();
+ b.ifZeroComparisonBranch(isInitialized, "!=");
+
+ // Load this in preparation for storing value to property.
+ b.loadThis();
+
+ // Call MasterSupport.getSequenceValueProducer(String).
+ TypeDesc seqValueProdType = TypeDesc.forClass(SequenceValueProducer.class);
+ b.loadThis();
+ b.loadField(StorableGenerator.SUPPORT_FIELD_NAME, triggerSupportType);
+ b.checkCast(masterSupportType);
+ b.loadConstant(property.getSequenceName());
+ b.invokeInterface
+ (masterSupportType, "getSequenceValueProducer",
+ seqValueProdType, new TypeDesc[] {TypeDesc.STRING});
+
+ // Find appropriate method to call for getting next sequence value.
+ TypeDesc propertyType = TypeDesc.forClass(property.getType());
+ TypeDesc propertyObjType = propertyType.toObjectType();
+ Method method;
+
+ try {
+ if (propertyObjType == TypeDesc.LONG.toObjectType()) {
+ method = SequenceValueProducer.class
+ .getMethod("nextLongValue", (Class[]) null);
+ } else if (propertyObjType == TypeDesc.INT.toObjectType()) {
+ method = SequenceValueProducer.class
+ .getMethod("nextIntValue", (Class[]) null);
+ } else if (propertyObjType == TypeDesc.STRING) {
+ method = SequenceValueProducer.class
+ .getMethod("nextDecimalValue", (Class[]) null);
+ } else {
+ throw new SupportException
+ ("Unable to support sequence of type \"" +
+ TypeDesc.forClass(property.getType()).getFullName() +
+ "\" for property: " + property.getName());
+ }
+ } catch (NoSuchMethodException e) {
+ Error err = new NoSuchMethodError();
+ err.initCause(e);
+ throw err;
}
- } catch (NoSuchMethodException e) {
- Error err = new NoSuchMethodError();
- err.initCause(e);
- throw err;
+
+ b.invoke(method);
+ b.convert(TypeDesc.forClass(method.getReturnType()), propertyType);
+
+ // Store property
+ b.storeField(property.getName(), propertyType);
+
+ // Set state to dirty.
+ b.loadThis();
+ b.loadThis();
+ b.loadField(stateFieldName, TypeDesc.INT);
+ b.loadConstant(StorableGenerator.PROPERTY_STATE_DIRTY << shift);
+ b.math(Opcode.IOR);
+ b.storeField(stateFieldName, TypeDesc.INT);
+
+ isInitialized.setLocation();
}
-
- b.invoke(method);
- b.convert(TypeDesc.forClass(method.getReturnType()), propertyType);
-
- // Store property
- b.storeField(property.getName(), propertyType);
-
- // Set state to dirty.
- b.loadThis();
- b.loadThis();
- b.loadField(stateFieldName, TypeDesc.INT);
- b.loadConstant(StorableGenerator.PROPERTY_STATE_DIRTY << shift);
- b.math(Opcode.IOR);
- b.storeField(stateFieldName, TypeDesc.INT);
-
- isInitialized.setLocation();
+
+ ordinal++;
}
-
- ordinal++;
+
+ // We've tried our best to fill in missing values, now run the
+ // original check method.
}
- // We've tried our best to fill in missing values, now run the
- // original check method.
b.loadThis();
b.invokeSuper(mClassFile.getSuperClassName(),
StorableGenerator.CHECK_PK_FOR_INSERT_METHOD_NAME,
@@ -579,9 +636,27 @@ public final class MasterStorableGenerator<S extends Storable> { addExitTransaction(b, INSERT_OP, txnVar, tryStart);
}
}
-
+
// Add required protected doTryUpdate method.
addDoTryUpdate: {
+ if (mFeatures.contains(MasterFeature.PARTITIONING)) {
+ // Check that partition key exists in update operation
+
+ MethodInfo mi = mClassFile.addMethod
+ (Modifiers.PROTECTED,
+ StorableGenerator.CHECK_PK_FOR_UPDATE_METHOD_NAME,
+ null, null);
+ CodeBuilder b = new CodeBuilder(mi);
+
+ checkIfPartitionKeyPresent(b);
+
+ b.loadThis();
+ b.invokeSuper(mClassFile.getSuperClassName(),
+ StorableGenerator.CHECK_PK_FOR_UPDATE_METHOD_NAME,
+ null, null);
+ b.returnVoid();
+ }
+
MethodInfo mi = mClassFile.addMethod
(Modifiers.PROTECTED.toFinal(true),
StorableGenerator.DO_TRY_UPDATE_METHOD_NAME, TypeDesc.BOOLEAN, null);
@@ -818,6 +893,23 @@ public final class MasterStorableGenerator<S extends Storable> { // Add required protected doTryDelete method.
{
+ if (mFeatures.contains(MasterFeature.PARTITIONING)) {
+ // Check that partition key exists in delete operation
+ MethodInfo mi = mClassFile.addMethod
+ (Modifiers.PROTECTED,
+ StorableGenerator.CHECK_PK_FOR_DELETE_METHOD_NAME,
+ null, null);
+ CodeBuilder b = new CodeBuilder(mi);
+
+ checkIfPartitionKeyPresent(b);
+
+ b.loadThis();
+ b.invokeSuper(mClassFile.getSuperClassName(),
+ StorableGenerator.CHECK_PK_FOR_DELETE_METHOD_NAME,
+ null, null);
+ b.returnVoid();
+ }
+
MethodInfo mi = mClassFile.addMethod
(Modifiers.PROTECTED.toFinal(true),
StorableGenerator.DO_TRY_DELETE_METHOD_NAME, TypeDesc.BOOLEAN, null);
@@ -848,6 +940,25 @@ public final class MasterStorableGenerator<S extends Storable> { addExitTransaction(b, DELETE_OP, txnVar, tryStart);
}
}
+
+ // Check that partition key exists for Load
+ {
+ if (mFeatures.contains(MasterFeature.PARTITIONING)) {
+ MethodInfo mi = mClassFile.addMethod
+ (Modifiers.PROTECTED,
+ StorableGenerator.CHECK_PK_FOR_LOAD_METHOD_NAME,
+ null, null);
+ CodeBuilder b = new CodeBuilder(mi);
+
+ checkIfPartitionKeyPresent(b);
+
+ b.loadThis();
+ b.invokeSuper(mClassFile.getSuperClassName(),
+ StorableGenerator.CHECK_PK_FOR_LOAD_METHOD_NAME,
+ null, null);
+ b.returnVoid();
+ }
+ }
}
private void branchIfNull(CodeBuilder b, LocalVariable value, Label isNull) {
@@ -1241,6 +1352,22 @@ public final class MasterStorableGenerator<S extends Storable> { success.setLocation();
}
+ private void checkIfPartitionKeyPresent(CodeBuilder b) {
+ b.loadThis();
+ b.invokeVirtual(StorableGenerator.IS_PARTITION_KEY_INITIALIZED_METHOD_NAME, TypeDesc.BOOLEAN, null);
+ Label ptnkInitialized = b.createLabel();
+ b.ifZeroComparisonBranch(ptnkInitialized, "!=");
+
+ TypeDesc exType = TypeDesc.forClass(IllegalStateException.class);
+ b.newObject(exType);
+ b.dup();
+ b.loadConstant("Partition key not fully specified");
+ b.invokeConstructor(exType, new TypeDesc[] {TypeDesc.STRING});
+ b.throwObject();
+
+ ptnkInitialized.setLocation();
+ }
+
private static class PropertyCopy<S extends Storable> {
final StorableProperty<S> property;
final LocalVariable copyVar;
diff --git a/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java b/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java index 1cf4889..0aeb541 100644 --- a/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java +++ b/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java @@ -109,7 +109,8 @@ public final class StorableGenerator<S extends Storable> { public static final String
CHECK_PK_FOR_INSERT_METHOD_NAME = "checkPkForInsert$",
CHECK_PK_FOR_UPDATE_METHOD_NAME = "checkPkForUpdate$",
- CHECK_PK_FOR_DELETE_METHOD_NAME = "checkPkForDelete$";
+ CHECK_PK_FOR_DELETE_METHOD_NAME = "checkPkForDelete$",
+ CHECK_PK_FOR_LOAD_METHOD_NAME = "checkPkForLoad$";
/**
* Name of protected method in generated storable that returns false if any
@@ -117,6 +118,12 @@ public final class StorableGenerator<S extends Storable> { */
public static final String IS_PK_INITIALIZED_METHOD_NAME = "isPkInitialized$";
+ /**
+ * Name of protected method in generated storable that returns false if any
+ * partition keys are uninitialized.
+ */
+ public static final String IS_PARTITION_KEY_INITIALIZED_METHOD_NAME = "isPartitionKeyInitialized$";
+
/**
* Name prefix of protected method in generated storable that returns false
* if a specific alternate key is uninitialized. The complete name is
@@ -279,6 +286,9 @@ public final class StorableGenerator<S extends Storable> { * // Returns true if all primary key properties have been set.
* protected boolean isPkInitialized();
*
+ * // Returns true if all partition key properties have been set.
+ * protected boolean isPartitionKeyInitialized();
+ *
* // Returns true if all required data properties are set.
* // A required data property is a non-nullable, non-primary key.
* protected boolean isRequiredDataInitialized();
@@ -1011,6 +1021,13 @@ public final class StorableGenerator<S extends Storable> { CodeBuilder b = new CodeBuilder(mi);
+ // Add empty method that will be overrriden if there is a partition key to check that it is initialized
+ b.loadThis();
+ b.invokeVirtual(CHECK_PK_FOR_LOAD_METHOD_NAME, null, null);
+ CodeBuilder b1 = new CodeBuilder(mClassFile.addMethod(Modifiers.PROTECTED, CHECK_PK_FOR_LOAD_METHOD_NAME, null, null));
+ b1.loadThis();
+ b1.returnVoid();
+
// Check that primary key is initialized.
b.loadThis();
b.invokeVirtual(IS_PK_INITIALIZED_METHOD_NAME, TypeDesc.BOOLEAN, null);
@@ -1697,6 +1714,20 @@ public final class StorableGenerator<S extends Storable> { addIsInitializedMethod
(IS_PK_INITIALIZED_METHOD_NAME, mInfo.getPrimaryKeyProperties());
+ {
+ // Define protected isPartitionKeyInitialized method
+ // It will return true if there are no Partition keys
+ final Map<String, StorableProperty<S>> partitionProperties = new LinkedHashMap<String, StorableProperty<S>>();
+ for (StorableProperty<S> property : mAllProperties.values()) {
+ if (!property.isDerived() && property.isPartitionKeyMember()) {
+ partitionProperties.put(property.getName(), property);
+ }
+ }
+
+ // Add methods to check that the partition key is defined
+ addIsInitializedMethod(IS_PARTITION_KEY_INITIALIZED_METHOD_NAME, partitionProperties);
+ }
+
// Define protected methods to check if alternate key is initialized.
addAltKeyMethods:
for (int i=0; i<mInfo.getAlternateKeyCount(); i++) {
|