summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java36
-rw-r--r--src/main/java/com/amazon/carbonado/gen/MasterStorableGenerator.java47
-rw-r--r--src/main/java/com/amazon/carbonado/layout/LayoutProperty.java8
3 files changed, 91 insertions, 0 deletions
diff --git a/src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java b/src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java
index 82be9f2..f25d6f1 100644
--- a/src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java
+++ b/src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java
@@ -579,6 +579,42 @@ public class CodeBuilderUtil {
}
/**
+ * Generates code to push a blank value to the stack. For objects, it is
+ * null, and for primitive types it is zero or false.
+ */
+ public static void blankValue(CodeBuilder b, TypeDesc type) {
+ switch (type.getTypeCode()) {
+ default:
+ b.loadNull();
+ break;
+
+ case TypeDesc.BYTE_CODE:
+ case TypeDesc.CHAR_CODE:
+ case TypeDesc.SHORT_CODE:
+ case TypeDesc.INT_CODE:
+ b.loadConstant(0);
+ break;
+
+ case TypeDesc.BOOLEAN_CODE:
+ b.loadConstant(false);
+ break;
+
+ case TypeDesc.LONG_CODE:
+ b.loadConstant(0L);
+ break;
+
+ case TypeDesc.FLOAT_CODE:
+ b.loadConstant(0.0f);
+ break;
+
+ case TypeDesc.DOUBLE_CODE:
+
+ b.loadConstant(0.0);
+ break;
+ }
+ }
+
+ /**
* Determines which overloaded "with" method on Query should be bound to.
*/
public static TypeDesc bindQueryParam(Class clazz) {
diff --git a/src/main/java/com/amazon/carbonado/gen/MasterStorableGenerator.java b/src/main/java/com/amazon/carbonado/gen/MasterStorableGenerator.java
index 82d8c7a..21af6cf 100644
--- a/src/main/java/com/amazon/carbonado/gen/MasterStorableGenerator.java
+++ b/src/main/java/com/amazon/carbonado/gen/MasterStorableGenerator.java
@@ -403,12 +403,16 @@ public final class MasterStorableGenerator<S extends Storable> {
Label tryStart = addEnterTransaction(b, INSERT_OP, txnVar);
+ LocalVariable wasVersionInitVar = null;
if (mFeatures.contains(MasterFeature.VERSIONING)) {
if (!mInfo.getVersionProperty().isDerived()) {
// Only set if uninitialized.
b.loadThis();
b.invokeVirtual(StorableGenerator.IS_VERSION_INITIALIZED_METHOD_NAME,
TypeDesc.BOOLEAN, null);
+ wasVersionInitVar = b.createLocalVariable(null, TypeDesc.BOOLEAN);
+ b.storeLocal(wasVersionInitVar);
+ b.loadLocal(wasVersionInitVar);
Label isInitialized = b.createLabel();
b.ifZeroComparisonBranch(isInitialized, "!=");
addAdjustVersionProperty(b, null, 1);
@@ -535,6 +539,23 @@ public final class MasterStorableGenerator<S extends Storable> {
b.loadThis();
b.invokeVirtual(DO_TRY_INSERT_MASTER_METHOD_NAME, TypeDesc.BOOLEAN, null);
+
+ if (wasVersionInitVar != null) {
+ // Decide if version property needs to rollback to uninitialized.
+
+ b.dup();
+ Label noRollback = b.createLabel();
+ // Don't rollback if insert succeeded.
+ b.ifZeroComparisonBranch(noRollback, "!=");
+
+ b.loadLocal(wasVersionInitVar);
+ // Rollback only if version was automatically set.
+ b.ifZeroComparisonBranch(noRollback, "!=");
+ unsetVersionProperty(b);
+
+ noRollback.setLocation();
+ }
+
addNormalizationRollback(b, doTryStart, unnormalized);
if (tryStart == null) {
@@ -1080,6 +1101,32 @@ public final class MasterStorableGenerator<S extends Storable> {
b.invoke(versionProperty.getWriteMethod());
}
+ /**
+ * Sets the version property to its initial uninitialized state.
+ */
+ private void unsetVersionProperty(CodeBuilder b) throws SupportException {
+ StorableProperty<?> property = mInfo.getVersionProperty();
+
+ // Set the property state to uninitialized.
+ {
+ String stateFieldName =
+ StorableGenerator.PROPERTY_STATE_FIELD_NAME + (property.getNumber() >> 4);
+ b.loadThis();
+ b.loadThis();
+ b.loadField(stateFieldName, TypeDesc.INT);
+ int shift = (property.getNumber() & 0xf) * 2;
+ b.loadConstant(~(StorableGenerator.PROPERTY_STATE_MASK << shift));
+ b.math(Opcode.IAND);
+ b.storeField(stateFieldName, TypeDesc.INT);
+ }
+
+ // Zero the property value.
+ TypeDesc type = TypeDesc.forClass(property.getType());
+ b.loadThis();
+ CodeBuilderUtil.blankValue(b, type);
+ b.storeField(property.getName(), type);
+ }
+
private List<PropertyCopy> addNormalization(CodeBuilder b, boolean forUpdate) {
List<PropertyCopy> unnormalized = null;
diff --git a/src/main/java/com/amazon/carbonado/layout/LayoutProperty.java b/src/main/java/com/amazon/carbonado/layout/LayoutProperty.java
index a0ce48f..bf35073 100644
--- a/src/main/java/com/amazon/carbonado/layout/LayoutProperty.java
+++ b/src/main/java/com/amazon/carbonado/layout/LayoutProperty.java
@@ -20,6 +20,7 @@ package com.amazon.carbonado.layout;
import org.cojen.classfile.TypeDesc;
+import com.amazon.carbonado.FetchException;
import com.amazon.carbonado.PersistException;
import com.amazon.carbonado.SupportException;
@@ -187,6 +188,13 @@ public class LayoutProperty {
void store() throws PersistException {
if (!mStoredLayoutProperty.tryInsert()) {
+ StoredLayoutProperty existing = mStoredLayoutProperty.copy();
+ try {
+ existing.load();
+ existing.copyVersionProperty(mStoredLayoutProperty);
+ } catch (FetchException e) {
+ throw e.toPersistException();
+ }
mStoredLayoutProperty.update();
}
}