use of org.apache.geode.cache.query.IndexMaintenanceException in project geode by apache.
the class MapRangeIndexMaintenanceJUnitTest method testDuplicateKeysInRangeIndexOnLocalRegion.
/**
* Test index object's comapreTo Function implementation correctness for indexes.
*
* @throws Exception
*/
@Test
public void testDuplicateKeysInRangeIndexOnLocalRegion() throws Exception {
IndexManager.TEST_RANGEINDEX_ONLY = true;
// Create Partition Region
AttributesFactory af = new AttributesFactory();
af.setScope(Scope.LOCAL);
Portfolio p = new Portfolio(1, 1);
HashMap map1 = new HashMap();
map1.put("SUN", new TestObject("SUN", 1));
map1.put("IBM", new TestObject("IBM", 2));
p.positions = map1;
region = CacheUtils.createRegion("portfolio", af.create(), false);
qs = CacheUtils.getQueryService();
keyIndex1 = (IndexProtocol) qs.createIndex(INDEX_NAME, "positions[*]", "/portfolio");
assertTrue(keyIndex1 instanceof MapRangeIndex);
// Put duplicate TestObject with "IBM" name.
region.put(Integer.toString(1), p);
Portfolio p2 = new Portfolio(2, 2);
HashMap map2 = new HashMap();
map2.put("YHOO", new TestObject("YHOO", 3));
map2.put("IBM", new TestObject("IBM", 2));
p2.positions = map2;
region.put(Integer.toString(2), p2);
// Following destroy fails if fix for 44123 is not there.
try {
region.destroy(Integer.toString(1));
} catch (NullPointerException e) {
fail("Test Failed! region.destroy got NullPointerException!");
} catch (Exception ex) {
if (ex instanceof IndexMaintenanceException) {
if (!ex.getCause().getMessage().contains("compareTo function is errorneous")) {
fail("Test Failed! Did not get expected exception IMQException." + ex.getMessage());
}
} else {
ex.printStackTrace();
fail("Test Failed! Did not get expected exception IMQException.");
}
}
}
use of org.apache.geode.cache.query.IndexMaintenanceException in project geode by apache.
the class MapRangeIndexMaintenanceJUnitTest method testDuplicateKeysInCompactRangeIndexOnLocalRegion.
/**
* Test index object's comapreTo Function implementation correctness for indexes.
*
* @throws Exception
*/
@Test
public void testDuplicateKeysInCompactRangeIndexOnLocalRegion() throws Exception {
// Create Partition Region
AttributesFactory af = new AttributesFactory();
af.setScope(Scope.LOCAL);
Portfolio p = new Portfolio(1, 1);
HashMap map1 = new HashMap();
map1.put("SUN", new TestObject("SUN", 1));
map1.put("IBM", new TestObject("IBM", 2));
p.positions = map1;
region = CacheUtils.createRegion("portfolio", af.create(), false);
qs = CacheUtils.getQueryService();
keyIndex1 = (IndexProtocol) qs.createIndex(INDEX_NAME, "positions[*]", "/portfolio");
assertTrue(keyIndex1 instanceof CompactMapRangeIndex);
// Put duplicate TestObject with "IBM" name.
region.put(Integer.toString(1), p);
Portfolio p2 = new Portfolio(2, 2);
HashMap map2 = new HashMap();
map2.put("YHOO", new TestObject("YHOO", 3));
map2.put("IBM", new TestObject("IBM", 2));
p2.positions = map2;
region.put(Integer.toString(2), p2);
// Following destroy fails if fix for 44123 is not there.
try {
region.destroy(Integer.toString(1));
} catch (NullPointerException e) {
fail("Test Failed! region.destroy got NullPointerException!");
} catch (Exception ex) {
if (ex instanceof IndexMaintenanceException) {
if (!ex.getCause().getMessage().contains("compareTo function is errorneous")) {
fail("Test Failed! Did not get expected exception IMQException." + ex.getMessage());
}
} else {
ex.printStackTrace();
fail("Test Failed! Did not get expected exception IMQException.");
}
}
}
use of org.apache.geode.cache.query.IndexMaintenanceException in project geode by apache.
the class MemoryIndexStore method updateMapping.
@Override
public void updateMapping(Object indexKey, Object oldKey, RegionEntry re, Object oldValue) throws IMQException {
try {
if (DefaultQuery.testHook != null) {
DefaultQuery.testHook.doTestHook(3);
}
// Check if reverse-map is present.
if (IndexManager.isObjectModificationInplace()) {
// If reverse map get the old index key from reverse map.
if (this.entryToValuesMap.containsKey(re)) {
oldKey = this.entryToValuesMap.get(re);
}
} else {
// forward map.
if (oldValue != null && oldValue == getTargetObjectInVM(re)) {
oldKey = getOldKey(indexKey, re);
}
}
// No need to update the map if new and old index key are same.
if (oldKey != null && oldKey.equals(TypeUtils.indexKeyFor(indexKey))) {
return;
}
boolean retry = false;
indexKey = TypeUtils.indexKeyFor(indexKey);
if (indexKey.equals(QueryService.UNDEFINED)) {
Object targetObject = getTargetObjectForUpdate(re);
if (Token.isInvalidOrRemoved(targetObject)) {
if (oldKey != null) {
basicRemoveMapping(oldKey, re, false);
}
return;
}
}
do {
retry = false;
Object regionEntries = this.valueToEntriesMap.putIfAbsent(indexKey, re);
if (regionEntries == TRANSITIONING_TOKEN) {
retry = true;
continue;
} else if (regionEntries == null) {
internalIndexStats.incNumKeys(1);
numIndexKeys.incrementAndGet();
} else if (regionEntries instanceof RegionEntry) {
IndexElemArray elemArray = new IndexElemArray();
if (DefaultQuery.testHook != null) {
DefaultQuery.testHook.doTestHook("BEGIN_TRANSITION_FROM_REGION_ENTRY_TO_ELEMARRAY");
}
elemArray.add(regionEntries);
elemArray.add(re);
if (!this.valueToEntriesMap.replace(indexKey, regionEntries, elemArray)) {
retry = true;
}
if (DefaultQuery.testHook != null) {
DefaultQuery.testHook.doTestHook("TRANSITIONED_FROM_REGION_ENTRY_TO_ELEMARRAY");
}
if (DefaultQuery.testHook != null) {
DefaultQuery.testHook.doTestHook("COMPLETE_TRANSITION_FROM_REGION_ENTRY_TO_ELEMARRAY");
}
} else if (regionEntries instanceof IndexConcurrentHashSet) {
// basicRemoveMapping();
synchronized (regionEntries) {
((IndexConcurrentHashSet) regionEntries).add(re);
}
if (regionEntries != this.valueToEntriesMap.get(indexKey)) {
retry = true;
}
} else {
IndexElemArray elemArray = (IndexElemArray) regionEntries;
synchronized (elemArray) {
if (elemArray.size() >= IndexManager.INDEX_ELEMARRAY_THRESHOLD) {
IndexConcurrentHashSet set = new IndexConcurrentHashSet(IndexManager.INDEX_ELEMARRAY_THRESHOLD + 20, 0.75f, 1);
if (DefaultQuery.testHook != null) {
DefaultQuery.testHook.doTestHook("BEGIN_TRANSITION_FROM_ELEMARRAY_TO_CONCURRENT_HASH_SET");
}
// retry?
if (!this.valueToEntriesMap.replace(indexKey, regionEntries, TRANSITIONING_TOKEN)) {
retry = true;
} else {
if (DefaultQuery.testHook != null) {
DefaultQuery.testHook.doTestHook("TRANSITIONED_FROM_ELEMARRAY_TO_TOKEN");
}
set.add(re);
set.addAll(elemArray);
if (!this.valueToEntriesMap.replace(indexKey, TRANSITIONING_TOKEN, set)) {
// This should never happen. If we see this in the log, then something is wrong
// with the TRANSITIONING TOKEN and synchronization of changing collection types
// we should then just go from RE to CHS and completely remove the Elem Array.
region.getCache().getLogger().warning("Unable to transition from index elem to concurrent hash set. Index needs to be recreated");
throw new IndexMaintenanceException("Unable to transition from index elem to concurrent hash set. Index needs to be recreated");
}
if (DefaultQuery.testHook != null) {
DefaultQuery.testHook.doTestHook("COMPLETE_TRANSITION_FROM_ELEMARRAY_TO_CONCURRENT_HASH_SET");
}
}
} else {
elemArray.add(re);
if (regionEntries != this.valueToEntriesMap.get(indexKey)) {
retry = true;
}
}
}
}
// Add to reverse Map with the new value.
if (!retry) {
// oldKey is not null only for an update
if (oldKey != null) {
basicRemoveMapping(oldKey, re, false);
}
if (IndexManager.isObjectModificationInplace()) {
this.entryToValuesMap.put(re, indexKey);
}
}
} while (retry);
} catch (TypeMismatchException ex) {
throw new IMQException("Could not add object of type " + indexKey.getClass().getName(), ex);
}
internalIndexStats.incNumValues(1);
}
use of org.apache.geode.cache.query.IndexMaintenanceException in project geode by apache.
the class IndexManager method processAction.
/**
* @param opCode one of IndexProtocol.OTHER_OP, BEFORE_UPDATE_OP, AFTER_UPDATE_OP.
*/
private void processAction(RegionEntry entry, int action, int opCode) throws QueryException {
final long startPA = getCachePerfStats().startIndexUpdate();
DefaultQuery.setPdxReadSerialized(this.region.getCache(), true);
TXStateProxy tx = null;
if (!((InternalCache) this.region.getCache()).isClient()) {
tx = ((TXManagerImpl) this.region.getCache().getCacheTransactionManager()).internalSuspend();
}
try {
// creation thread
if (IndexManager.testHook != null) {
if (logger.isDebugEnabled()) {
logger.debug("IndexManager TestHook is set.");
}
// ConcurrentIndexInitOnOverflowRegionDUnitTest
testHook.hook(6);
}
long start = 0;
boolean indexLockAcquired = false;
switch(action) {
case ADD_ENTRY:
{
if (IndexManager.testHook != null) {
if (logger.isDebugEnabled()) {
logger.debug("IndexManager TestHook in ADD_ENTRY.");
}
testHook.hook(5);
}
// this action is only called after update
assert opCode == IndexProtocol.OTHER_OP;
// Asif The behaviour can arise if an index creation has already
// acted upon a newly added entry , but by the time callback
// occurs , the index is added to the map & thus
// the add operation will now have an effect of update.
// so we need to remove the mapping even if it is an Add action
// as otherwise the new results will get added into the
// old results instead of replacement
Iterator iter = this.indexes.values().iterator();
while (iter.hasNext()) {
Object ind = iter.next();
// the index is in create phase.
if (ind instanceof FutureTask) {
continue;
}
IndexProtocol index = (IndexProtocol) ind;
if (((AbstractIndex) index).isPopulated() && index.getType() != IndexType.PRIMARY_KEY) {
// apply IMQ on it
if (!index.containsEntry(entry)) {
if (logger.isDebugEnabled()) {
logger.debug("Adding to index: {}{} value: {}", index.getName(), this.region.getFullPath(), entry.getKey());
}
start = ((AbstractIndex) index).updateIndexUpdateStats();
index.addIndexMapping(entry);
((AbstractIndex) index).updateIndexUpdateStats(start);
}
}
}
break;
}
case UPDATE_ENTRY:
{
if (IndexManager.testHook != null) {
if (logger.isDebugEnabled()) {
logger.debug("IndexManager TestHook in UPDATE_ENTRY.");
}
testHook.hook(5);
// QueryDataInconsistencyDUnitTest
testHook.hook(9);
}
// this action is only called with opCode AFTER_UPDATE_OP
assert opCode == IndexProtocol.AFTER_UPDATE_OP;
Iterator iter = this.indexes.values().iterator();
while (iter.hasNext()) {
Object ind = iter.next();
// the index is in create phase.
if (ind instanceof FutureTask) {
continue;
}
IndexProtocol index = (IndexProtocol) ind;
if (((AbstractIndex) index).isPopulated() && index.getType() != IndexType.PRIMARY_KEY) {
if (logger.isDebugEnabled()) {
logger.debug("Updating index: {}{} value: {}", index.getName(), this.region.getFullPath(), entry.getKey());
}
start = ((AbstractIndex) index).updateIndexUpdateStats();
index.addIndexMapping(entry);
((AbstractIndex) index).updateIndexUpdateStats(start);
}
}
break;
}
case REMOVE_ENTRY:
{
if (IndexManager.testHook != null) {
if (logger.isDebugEnabled()) {
logger.debug("IndexManager TestHook in REMOVE_ENTRY.");
}
testHook.hook(5);
testHook.hook(10);
}
Iterator iter = this.indexes.values().iterator();
while (iter.hasNext()) {
Object ind = iter.next();
// the index is in create phase.
if (ind instanceof FutureTask) {
continue;
}
IndexProtocol index = (IndexProtocol) ind;
if (((AbstractIndex) index).isPopulated() && index.getType() != IndexType.PRIMARY_KEY) {
AbstractIndex abstractIndex = (AbstractIndex) index;
if (logger.isDebugEnabled()) {
logger.debug("Removing from index: {}{} value: {}", index.getName(), this.region.getFullPath(), entry.getKey());
}
start = ((AbstractIndex) index).updateIndexUpdateStats();
index.removeIndexMapping(entry, opCode);
((AbstractIndex) index).updateIndexUpdateStats(start);
}
}
break;
}
default:
{
throw new IndexMaintenanceException(LocalizedStrings.IndexManager_INVALID_ACTION.toLocalizedString());
}
}
} finally {
DefaultQuery.setPdxReadSerialized(this.region.getCache(), false);
if (tx != null) {
((TXManagerImpl) this.region.getCache().getCacheTransactionManager()).internalResume(tx);
}
getCachePerfStats().endIndexUpdate(startPA);
}
}
use of org.apache.geode.cache.query.IndexMaintenanceException in project geode by apache.
the class AbstractRegionEntry method destroy.
/**
* @throws EntryNotFoundException if expectedOldValue is not null and is not equal to current
* value
*/
@Override
@Released
public boolean destroy(LocalRegion region, EntryEventImpl event, boolean inTokenMode, boolean cacheWrite, @Unretained Object expectedOldValue, boolean forceDestroy, boolean removeRecoveredEntry) throws CacheWriterException, EntryNotFoundException, TimeoutException, RegionClearedException {
// A design decision was made to not retrieve the old value from the disk
// if the entry has been evicted to only have the CacheListener afterDestroy
// method ignore it. We don't want to pay the performance penalty. The
// getValueInVM method does not retrieve the value from disk if it has been
// evicted. Instead, it uses the NotAvailable token.
//
// If the region is a WAN queue region, the old value is actually used by the
// afterDestroy callback on a secondary. It is not needed on a primary.
// Since the destroy that sets WAN_QUEUE_TOKEN always originates on the primary
// we only pay attention to WAN_QUEUE_TOKEN if the event is originRemote.
//
// We also read old value from disk or buffer
// in the case where there is a non-null expectedOldValue
// see PartitionedRegion#remove(Object key, Object value)
ReferenceCountHelper.skipRefCountTracking();
@Retained @Released Object curValue = _getValueRetain(region, true);
ReferenceCountHelper.unskipRefCountTracking();
boolean proceed;
try {
if (curValue == null) {
curValue = Token.NOT_AVAILABLE;
}
if (curValue == Token.NOT_AVAILABLE) {
// the state of the transmitting cache's entry & should be used here
if (event.getCallbackArgument() != null && event.getCallbackArgument().equals(RegionQueue.WAN_QUEUE_TOKEN) && event.isOriginRemote()) {
// check originRemote for bug 40508
// curValue = getValue(region); can cause deadlock if GII is occurring
curValue = getValueOnDiskOrBuffer(region);
} else {
FilterProfile fp = region.getFilterProfile();
if (fp != null && (fp.getCqCount() > 0 || expectedOldValue != null)) {
// curValue = getValue(region); can cause deadlock will fault in the value
// and will confuse LRU.
curValue = getValueOnDiskOrBuffer(region);
}
}
}
if (expectedOldValue != null) {
if (!checkExpectedOldValue(expectedOldValue, curValue, region)) {
throw new EntryNotFoundException(LocalizedStrings.AbstractRegionEntry_THE_CURRENT_VALUE_WAS_NOT_EQUAL_TO_EXPECTED_VALUE.toLocalizedString());
}
}
if (inTokenMode && event.hasOldValue()) {
proceed = true;
} else {
proceed = event.setOldValue(curValue, curValue instanceof GatewaySenderEventImpl) || removeRecoveredEntry || forceDestroy || region.getConcurrencyChecksEnabled() || (event.getOperation() == Operation.REMOVE && (curValue == null || curValue == Token.LOCAL_INVALID || curValue == Token.INVALID));
}
} finally {
OffHeapHelper.releaseWithNoTracking(curValue);
}
if (proceed) {
// after the entry not found exception above.
if (!removeRecoveredEntry) {
region.generateAndSetVersionTag(event, this);
}
if (cacheWrite) {
region.cacheWriteBeforeDestroy(event, expectedOldValue);
if (event.getRegion().getServerProxy() != null) {
// server will return a version tag
// update version information (may throw ConcurrentCacheModificationException)
VersionStamp stamp = getVersionStamp();
if (stamp != null) {
stamp.processVersionTag(event);
}
}
}
region.recordEvent(event);
// RegionEntry (the old value) is invalid
if (!region.isProxy() && !isInvalid()) {
IndexManager indexManager = region.getIndexManager();
if (indexManager != null) {
try {
if (isValueNull()) {
@Released Object value = getValueOffHeapOrDiskWithoutFaultIn(region);
try {
Object preparedValue = prepareValueForCache(region, value, false);
_setValue(preparedValue);
releaseOffHeapRefIfRegionBeingClosedOrDestroyed(region, preparedValue);
} finally {
OffHeapHelper.release(value);
}
}
indexManager.updateIndexes(this, IndexManager.REMOVE_ENTRY, IndexProtocol.OTHER_OP);
} catch (QueryException e) {
throw new IndexMaintenanceException(e);
}
}
}
boolean removeEntry = false;
VersionTag v = event.getVersionTag();
if (region.concurrencyChecksEnabled && !removeRecoveredEntry && !event.isFromRILocalDestroy()) {
// Destroy will write a tombstone instead
if (v == null || !v.hasValidVersion()) {
// localDestroy and eviction and ops received with no version tag
// should create a tombstone using the existing version stamp, as should
// (bug #45245) responses from servers that do not have valid version information
VersionStamp stamp = this.getVersionStamp();
if (stamp != null) {
// proxy has no stamps
v = stamp.asVersionTag();
event.setVersionTag(v);
}
}
removeEntry = v == null || !v.hasValidVersion();
} else {
removeEntry = true;
}
if (removeEntry) {
boolean isThisTombstone = isTombstone();
if (inTokenMode && !event.getOperation().isEviction()) {
setValue(region, Token.DESTROYED);
} else {
removePhase1(region, false);
}
if (isThisTombstone) {
region.unscheduleTombstone(this);
}
} else {
makeTombstone(region, v);
}
return true;
} else {
return false;
}
}
Aggregations