diff --git a/gemfirexd/core/src/main/java/com/pivotal/gemfirexd/internal/engine/access/operations/SortedMap2IndexInsertOperation.java b/gemfirexd/core/src/main/java/com/pivotal/gemfirexd/internal/engine/access/operations/SortedMap2IndexInsertOperation.java index d447ee412..72c2feb82 100644 --- a/gemfirexd/core/src/main/java/com/pivotal/gemfirexd/internal/engine/access/operations/SortedMap2IndexInsertOperation.java +++ b/gemfirexd/core/src/main/java/com/pivotal/gemfirexd/internal/engine/access/operations/SortedMap2IndexInsertOperation.java @@ -22,13 +22,7 @@ import com.gemstone.gemfire.cache.ConflictException; import com.gemstone.gemfire.cache.query.IndexMaintenanceException; import com.gemstone.gemfire.i18n.LogWriterI18n; -import com.gemstone.gemfire.internal.cache.AbstractRegionEntry; -import com.gemstone.gemfire.internal.cache.GemFireCacheImpl; -import com.gemstone.gemfire.internal.cache.ObjectEqualsHashingStrategy; -import com.gemstone.gemfire.internal.cache.OffHeapRegionEntry; -import com.gemstone.gemfire.internal.cache.TXEntryState; -import com.gemstone.gemfire.internal.cache.TXId; -import com.gemstone.gemfire.internal.cache.TXStateInterface; +import com.gemstone.gemfire.internal.cache.*; import com.gemstone.gemfire.internal.cache.locks.ExclusiveSharedSynchronizer; import com.gemstone.gemfire.internal.cache.locks.LockMode; import com.gemstone.gemfire.internal.cache.locks.LockingPolicy; @@ -408,11 +402,23 @@ public Object updateValue(Object key, Object oldValue, RowLocation value, return null; } else if ((oldValueClass = oldValue.getClass()) == RowLocation[].class) { - return insertToRowLocationArray(container, key, value, - (RowLocation[])oldValue, this.isPutDML); + RowLocation[] oldArr = (RowLocation[]) oldValue; + if (oldArr.length == 1 ) { + return insertToRowLocation(container, key, value, + oldArr[0], this.isPutDML); + } else { + return insertToRowLocationArray(container, key, value, + (RowLocation[])oldValue, this.isPutDML); + } } else if (oldValueClass == ConcurrentTHashSet.class) { - return insertToHashSet(container, key, value, oldValue, this.isPutDML); + ConcurrentTHashSet x = (ConcurrentTHashSet) oldValue; + if (x.size() == 1) { + return insertToRowLocation(container, key, value, + (RowLocation)x.iterator().next(), this.isPutDML); + } else { + return insertToHashSet(container, key, value, oldValue, this.isPutDML); + } } else if (RowLocation.class.isAssignableFrom(oldValueClass)) { return insertToRowLocation(container, key, value, @@ -492,6 +498,15 @@ private static Object insertToRowLocation(GemFireContainer container, container.getQualifiedTableName(), oldValue, insertedValue)); } + if (oldValue instanceof WrapperRowLocationForTxn && insertedValue instanceof WrapperRowLocationForTxn + && oldValue.equals(insertedValue)) { + /*WrapperRowLocationForTxn e1 = (WrapperRowLocationForTxn) oldValue; + WrapperRowLocationForTxn e2 = (WrapperRowLocationForTxn) insertedValue; + if (e1.getTXId().equals(e2.getTXId()) && e1.getRegionEntry() == e2.getRegionEntry()) { + return insertedValue; + } */ + return insertedValue; + } RowLocation[] newValues = new RowLocation[2]; newValues[0] = oldValue; newValues[1] = insertedValue; @@ -514,6 +529,7 @@ private static Object insertToRowLocationArray( numExistingValues + 1, 0.60f, ObjectEqualsHashingStrategy.getInstance(), container .getBaseContainer().getRegion().getRegionPerfStats()); + boolean skipIfSameTxEntry = false; for (int i = 0; i < numExistingValues; i++) { // should not happen when a duplicate entry from both GII and create // will be converted to an update by GFE and handled properly by @@ -528,10 +544,25 @@ private static Object insertToRowLocationArray( GemFireXDUtils.newDuplicateEntryViolation( container.getQualifiedTableName(), existingValues[i], insertedValue)); + } else { + skipIfSameTxEntry = insertedValue instanceof WrapperRowLocationForTxn && + existingValues[i] instanceof WrapperRowLocationForTxn && + insertedValue.equals(existingValues[i]); + /* + if (insertedValue instanceof WrapperRowLocationForTxn) { + if (existingValues[i] instanceof WrapperRowLocationForTxn) { + skipIfSameTxEntry = ((WrapperRowLocationForTxn)existingValues[i]).getTXId().equals( + ((WrapperRowLocationForTxn)insertedValue).getTXId()) && + ((WrapperRowLocationForTxn)existingValues[i]).getRegionEntry() == + ((WrapperRowLocationForTxn)insertedValue).getRegionEntry(); + } + } */ } set.add(existingValues[i]); } - set.add(insertedValue); + if (!skipIfSameTxEntry) { + set.add(insertedValue); + } return set; } else { @@ -550,6 +581,22 @@ private static Object insertToRowLocationArray( GemFireXDUtils.newDuplicateEntryViolation( container.getQualifiedTableName(), existingValues[i], insertedValue)); + } else { + boolean isTxSame = insertedValue instanceof WrapperRowLocationForTxn && + existingValues[i] instanceof WrapperRowLocationForTxn + && insertedValue.equals(existingValues[i]); + + /*if (insertedValue instanceof WrapperRowLocationForTxn ) { + if (existingValues[i] instanceof WrapperRowLocationForTxn) { + isTxSame = ((WrapperRowLocationForTxn)existingValues[i]).getTXId().equals( + ((WrapperRowLocationForTxn)insertedValue).getTXId()) && + ((WrapperRowLocationForTxn)existingValues[i]).getRegionEntry() == + ((WrapperRowLocationForTxn)insertedValue).getRegionEntry(); + } + } */ + if (isTxSame) { + return existingValues; + } } newValues[i] = existingValues[i]; } @@ -570,19 +617,24 @@ private static Object insertToHashSet(GemFireContainer container, Object key, final ConcurrentTHashSet set = (ConcurrentTHashSet)oldValue; + Object oldRowLocObj; if ((oldRowLocObj = set.addKey(insertedValue)) == null || isPutDML) { return set; } assert oldRowLocObj.equals(insertedValue); - // should not happen when a duplicate entry from both GII and create - // will be converted to an update by GFE and handled properly by - // GfxdIndexManager#onEvent(); - // can happen in case update is fired on index column updating to the - // old value itself - throw new IndexMaintenanceException( - GemFireXDUtils.newDuplicateEntryViolation( - container.getQualifiedTableName(), oldRowLocObj, insertedValue)); + if (!(oldRowLocObj instanceof WrapperRowLocationForTxn && insertedValue instanceof WrapperRowLocationForTxn)) { + // should not happen when a duplicate entry from both GII and create + // will be converted to an update by GFE and handled properly by + // GfxdIndexManager#onEvent(); + // can happen in case update is fired on index column updating to the + // old value itself + throw new IndexMaintenanceException( + GemFireXDUtils.newDuplicateEntryViolation( + container.getQualifiedTableName(), oldRowLocObj, insertedValue)); + } else { + return set; + } } static final class ReplaceValue extends UpdateReplacementValue { @@ -603,10 +655,19 @@ public Object replaceValue(Object key, Object oldValue, } else if ((mapValueClass = existingValue.getClass()) == RowLocation[].class) { - return replaceRowLocationArray(container, key, oldValue, - (RowLocation)newValue, (RowLocation[])existingValue, this.isPutDML); + RowLocation[] arr = (RowLocation[])existingValue; + if (arr.length == 1) { + return newValue; + } else { + return replaceRowLocationArray(container, key, oldValue, + (RowLocation)newValue, (RowLocation[])existingValue, this.isPutDML); + } } else if (mapValueClass == ConcurrentTHashSet.class) { + ConcurrentTHashSet x = (ConcurrentTHashSet)existingValue; + if (x.size() == 1) { + return newValue; + } return replaceInHashSet(container, key, oldValue, newValue, existingValue); } @@ -649,16 +710,45 @@ private static RowLocation[] replaceRowLocationArray( // GfxdIndexManager#onEvent(); // can happen in case update is fired on index column updating to the // old value itself - if (insertedValue != existingValue) { - if (oldValue != existingValue) { - try { - newValues[++index] = existingValue; - } catch (ArrayIndexOutOfBoundsException ae) { - // throw back a proper exception for the case when value to be - // replaced is not found - throw new IndexMaintenanceException( - GemFireXDUtils.newOldValueNotFoundException(key, oldValue, - existingValues, container)); + + /* + boolean isTxSame = false; + if (insertedValue instanceof WrapperRowLocationForTxn ) { + /* if (existingValue instanceof RegionEntry) { + isTxSame = ((WrapperRowLocationForTxn)insertedValue).getRegionEntry() == existingValue; + } else*/ /* if (existingValue instanceof WrapperRowLocationForTxn) { + isTxSame = ((WrapperRowLocationForTxn)existingValue).getTXId().equals( + ((WrapperRowLocationForTxn)insertedValue).getTXId()) && + ((WrapperRowLocationForTxn)existingValue).getRegionEntry() == + ((WrapperRowLocationForTxn)insertedValue).getRegionEntry(); + } + } */ + boolean isTxSame = insertedValue instanceof WrapperRowLocationForTxn + && existingValue instanceof WrapperRowLocationForTxn && + insertedValue.equals(existingValue); + + + + + if (insertedValue != existingValue ) { + if (isTxSame) { + //do not add this value as we wil add inserted value to 0 position + foundOldValue = true; + } else if (oldValue != existingValue) { + if (oldValue instanceof TXEntryState && + ((TXEntryState)oldValue).getOriginalValue() == existingValue) { + //do not add this value as we wil add inserted value to 0 position + foundOldValue = true; + } else { + try { + newValues[++index] = existingValue; + } catch (ArrayIndexOutOfBoundsException ae) { + // throw back a proper exception for the case when value to be + // replaced is not found + throw new IndexMaintenanceException( + GemFireXDUtils.newOldValueNotFoundException(key, oldValue, + existingValues, container)); + } } } else if (!foundOldValue) { @@ -698,10 +788,16 @@ private static ConcurrentTHashSet replaceInHashSet( final ConcurrentTHashSet set = (ConcurrentTHashSet)existingValue; + // TODO: Asif : How to conflate two WrapperRowLocationTxn? May be that situation does not arise? if (set.replace(oldValue, insertedValue)) { return set; } else { + if (oldValue instanceof TXEntryState ) { + if (set.replace(((TXEntryState)oldValue).getOriginalValue(), insertedValue)) { + return set; + } + } // throw back a proper exception for the case when value to be // replaced is not found throw new IndexMaintenanceException( diff --git a/gemfirexd/core/src/main/java/com/pivotal/gemfirexd/internal/iapi/types/WrapperRowLocationForTxn.java b/gemfirexd/core/src/main/java/com/pivotal/gemfirexd/internal/iapi/types/WrapperRowLocationForTxn.java index 82b19c4b6..aeb3280bc 100644 --- a/gemfirexd/core/src/main/java/com/pivotal/gemfirexd/internal/iapi/types/WrapperRowLocationForTxn.java +++ b/gemfirexd/core/src/main/java/com/pivotal/gemfirexd/internal/iapi/types/WrapperRowLocationForTxn.java @@ -49,6 +49,29 @@ public WrapperRowLocationForTxn(GfxdTXEntryState rowLocationToBeWrapped, this.createdForUpdateOperation = forUpdateOp; } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj instanceof WrapperRowLocationForTxn && this.actualRowLocation != null + && ((WrapperRowLocationForTxn)obj).actualRowLocation != null) { + WrapperRowLocationForTxn that = (WrapperRowLocationForTxn) obj; + return this.actualRowLocation.equals(that.actualRowLocation); + } else { + return false; + } + } + + @Override + public int hashCode() { + int h = 17; + // h = h * 37 + this.indexContainer.hashCode(); + // h = h * 37 + this.indexKey.hashCode(); + h = h * 37 + (this.actualRowLocation != null ? this.actualRowLocation.hashCode() : super.hashCode()); + return h; + } + public boolean wasCreatedForUpdateOp() { return this.createdForUpdateOperation; }