Search in sources :

Example 26 with RegionVersionVector

use of org.apache.geode.internal.cache.versions.RegionVersionVector in project geode by apache.

the class DiskInitFile method cmnClearRegion.

public void cmnClearRegion(long drId, ConcurrentHashMap<DiskStoreID, RegionVersionHolder<DiskStoreID>> memberToVersion) {
    DiskRegionView drv = getDiskRegionById(drId);
    if (drv.getClearRVV() == null) {
        this.ifLiveRecordCount++;
    }
    // otherwise previous clear is cancelled so don't change liveRecordCount
    this.ifTotalRecordCount++;
    DiskStoreID ownerId = parent.getDiskStoreID();
    // Create a fake RVV for clear purposes. We only need to memberToVersion information
    RegionVersionHolder<DiskStoreID> ownerExceptions = memberToVersion.remove(ownerId);
    long ownerVersion = ownerExceptions == null ? 0 : ownerExceptions.getVersion();
    RegionVersionVector rvv = new DiskRegionVersionVector(ownerId, memberToVersion, ownerVersion, new ConcurrentHashMap(), 0L, false, ownerExceptions);
    drv.setClearRVV(rvv);
}
Also used : DiskRegionVersionVector(org.apache.geode.internal.cache.versions.DiskRegionVersionVector) DiskRegionVersionVector(org.apache.geode.internal.cache.versions.DiskRegionVersionVector) RegionVersionVector(org.apache.geode.internal.cache.versions.RegionVersionVector) DiskStoreID(org.apache.geode.internal.cache.persistence.DiskStoreID) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) DiskRegionView(org.apache.geode.internal.cache.persistence.DiskRegionView)

Example 27 with RegionVersionVector

use of org.apache.geode.internal.cache.versions.RegionVersionVector in project geode by apache.

the class Oplog method basicModify.

/**
   * A helper function which identifies whether to modify the entry in the current oplog or to make
   * the switch to the next oplog. This function enables us to reuse the byte buffer which got
   * created for an oplog which no longer permits us to use itself. It will also take acre of
   * compaction if required
   * 
   * @param entry DiskEntry object representing the current Entry
   */
private void basicModify(DiskRegionView dr, DiskEntry entry, ValueWrapper value, byte userBits, boolean async, boolean calledByCompactor) throws IOException, InterruptedException {
    DiskId id = entry.getDiskId();
    boolean useNextOplog = false;
    long startPosForSynchOp = -1L;
    int adjustment = 0;
    Oplog emptyOplog = null;
    if (DiskStoreImpl.KRF_DEBUG) {
        // wait for cache close to create krf
        System.out.println("basicModify KRF_DEBUG");
        Thread.sleep(1000);
    }
    synchronized (this.lock) {
        // synchronized (this.crf) {
        if (getOplogSet().getChild() != this) {
            useNextOplog = true;
        } else {
            initOpState(OPLOG_MOD_ENTRY_1ID, dr, entry, value, userBits, false);
            adjustment = getOpStateSize();
            assert adjustment > 0;
            long temp = (this.crf.currSize + adjustment);
            if (temp > getMaxCrfSize() && !isFirstRecord()) {
                switchOpLog(dr, adjustment, entry);
                // we can't reuse it since it contains variable length data
                useNextOplog = true;
            } else {
                if (this.lockedForKRFcreate) {
                    CacheClosedException cce = new CacheClosedException("The disk store is closed.");
                    dr.getCancelCriterion().checkCancelInProgress(cce);
                    throw cce;
                }
                this.firstRecord = false;
                long oldOplogId;
                // do the io while holding lock so that switch can set doneAppending
                // Write the data to the opLog for the synch mode
                startPosForSynchOp = writeOpLogBytes(this.crf, async, true);
                this.crf.currSize = temp;
                startPosForSynchOp += getOpStateValueOffset();
                if (logger.isTraceEnabled(LogMarker.PERSIST_WRITES)) {
                    VersionTag tag = null;
                    if (entry.getVersionStamp() != null) {
                        tag = entry.getVersionStamp().asVersionTag();
                    }
                    logger.trace(LogMarker.PERSIST_WRITES, "basicModify: id=<{}> key=<{}> valueOffset={} userBits={} valueLen={} valueBytes=<{}> drId={} versionStamp={} oplog#{}", abs(id.getKeyId()), entry.getKey(), startPosForSynchOp, userBits, value.getLength(), value.getBytesAsString(), dr.getId(), tag, getOplogId());
                }
                if (EntryBits.isNeedsValue(userBits)) {
                    id.setValueLength(value.getLength());
                } else {
                    id.setValueLength(0);
                }
                id.setUserBits(userBits);
                if (logger.isTraceEnabled()) {
                    logger.trace("Oplog::basicModify:Released ByteBuffer with data for Disk ID = {}", id);
                }
                synchronized (id) {
                    // Need to do this while synced on id
                    // now that we compact forward to most recent oplog.
                    // @todo darrel: The sync logic in the disk code is so complex
                    // a really doubt is is correct.
                    // I think we need to do a fresh rewrite of it.
                    oldOplogId = id.setOplogId(getOplogId());
                    if (EntryBits.isAnyInvalid(userBits) || EntryBits.isTombstone(userBits)) {
                        id.setOffsetInOplog(-1);
                    } else {
                        id.setOffsetInOplog(startPosForSynchOp);
                    }
                }
                // Set the oplog size change for stats
                this.dirHolder.incrementTotalOplogSize(adjustment);
                this.incTotalCount();
                EntryLogger.logPersistPut(dr.getName(), entry.getKey(), dr.getDiskStoreID());
                if (oldOplogId != getOplogId()) {
                    Oplog oldOplog = getOplogSet().getChild(oldOplogId);
                    if (oldOplog != null) {
                        oldOplog.rmLive(dr, entry);
                        emptyOplog = oldOplog;
                    }
                    addLive(dr, entry);
                // Note if this mod was done to oldOplog then this entry is already
                // in
                // the linked list. All we needed to do in this case is call
                // incTotalCount
                } else {
                    getOrCreateDRI(dr).update(entry);
                }
                // Update the region version vector for the disk store.
                // This needs to be done under lock so that we don't switch oplogs
                // unit the version vector accurately represents what is in this oplog
                RegionVersionVector rvv = dr.getRegionVersionVector();
                if (rvv != null && entry.getVersionStamp() != null) {
                    rvv.recordVersion(entry.getVersionStamp().getMemberID(), entry.getVersionStamp().getRegionVersion());
                }
            }
            clearOpState();
        }
    // }
    }
    if (useNextOplog) {
        if (LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER) {
            CacheObserverHolder.getInstance().afterSwitchingOplog();
        }
        Assert.assertTrue(getOplogSet().getChild() != this);
        getOplogSet().getChild().basicModify(dr, entry, value, userBits, async, calledByCompactor);
    } else {
        if (LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER) {
            CacheObserverHolder.getInstance().afterSettingOplogOffSet(startPosForSynchOp);
        }
        if (emptyOplog != null && (!emptyOplog.isCompacting() || emptyOplog.calledByCompactorThread())) {
            if (calledByCompactor && emptyOplog.hasNoLiveValues()) {
                // Since compactor will only append to crf no need to flush drf.
                // Before we have the compactor delete an oplog it has emptied out
                // we want to have it flush anything it has written to the current
                // oplog.
                // Note that since sync writes may be done to the same oplog we are
                // doing
                // async writes to any sync writes will cause a flush to be done
                // immediately.
                flushAll(true);
            }
            emptyOplog.handleNoLiveValues();
        }
    }
}
Also used : VersionTag(org.apache.geode.internal.cache.versions.VersionTag) RegionVersionVector(org.apache.geode.internal.cache.versions.RegionVersionVector) CacheClosedException(org.apache.geode.cache.CacheClosedException)

Example 28 with RegionVersionVector

use of org.apache.geode.internal.cache.versions.RegionVersionVector in project geode by apache.

the class LocalRegion method createVersionVector.

/** initializes a new version vector for this region */
void createVersionVector() {
    this.versionVector = RegionVersionVector.create(getVersionMember(), this);
    if (this.dataPolicy.withPersistence()) {
        // copy the versions that we have recovered from disk into
        // the version vector.
        RegionVersionVector diskVector = this.diskRegion.getRegionVersionVector();
        this.versionVector.recordVersions(diskVector.getCloneForTransmission());
    } else if (!this.dataPolicy.withStorage()) {
        // version vectors are currently only necessary in empty regions for
        // tracking canonical member IDs
        this.versionVector.turnOffRecordingForEmptyRegion();
    }
    if (this.serverRegionProxy != null) {
        this.versionVector.setIsClientVector();
    }
    this.cache.getDistributionManager().addMembershipListener(this.versionVector);
}
Also used : RegionVersionVector(org.apache.geode.internal.cache.versions.RegionVersionVector)

Example 29 with RegionVersionVector

use of org.apache.geode.internal.cache.versions.RegionVersionVector in project geode by apache.

the class Oplog method basicCreate.

/**
   * A helper function which identifies whether to create the entry in the current oplog or to make
   * the switch to the next oplog. This function enables us to reuse the byte buffer which got
   * created for an oplog which no longer permits us to use itself
   * 
   * @param entry DiskEntry object representing the current Entry
   */
private void basicCreate(DiskRegion dr, DiskEntry entry, ValueWrapper value, byte userBits, boolean async) throws IOException, InterruptedException {
    DiskId id = entry.getDiskId();
    boolean useNextOplog = false;
    long startPosForSynchOp = -1;
    if (DiskStoreImpl.KRF_DEBUG) {
        // wait for cache close to create krf
        System.out.println("basicCreate KRF_DEBUG");
        Thread.sleep(1000);
    }
    synchronized (this.lock) {
        // TODO soplog perf analysis shows this as a
        // contention point
        // synchronized (this.crf) {
        initOpState(OPLOG_NEW_ENTRY_0ID, dr, entry, value, userBits, false);
        // Check if the current data in ByteBuffer will cause a
        // potential increase in the size greater than the max allowed
        long temp = (getOpStateSize() + this.crf.currSize);
        if (!this.wroteNewEntryBase) {
            temp += OPLOG_NEW_ENTRY_BASE_REC_SIZE;
        }
        if (this != getOplogSet().getChild()) {
            useNextOplog = true;
        } else if (temp > getMaxCrfSize() && !isFirstRecord()) {
            switchOpLog(dr, getOpStateSize(), entry);
            useNextOplog = true;
        } else {
            if (this.lockedForKRFcreate) {
                CacheClosedException cce = new CacheClosedException("The disk store is closed.");
                dr.getCancelCriterion().checkCancelInProgress(cce);
                throw cce;
            }
            this.firstRecord = false;
            writeNewEntryBaseRecord(async);
            // Now we can finally call newOplogEntryId.
            // We need to make sure the create records
            // are written in the same order as they are created.
            // This allows us to not encode the oplogEntryId explicitly in the
            // record
            long createOplogEntryId = getOplogSet().newOplogEntryId();
            id.setKeyId(createOplogEntryId);
            // startPosForSynchOp = this.crf.currSize;
            // Allow it to be added to the OpLOg so increase the
            // size of currenstartPosForSynchOpt oplog
            int dataLength = getOpStateSize();
            // It is necessary that we set the
            // Oplog ID here without releasing the lock on object as we are
            // writing to the file after releasing the lock. This can cause
            // a situation where the
            // switching thread has added Oplog for compaction while the previous
            // thread has still not started writing. Thus compactor can
            // miss an entry as the oplog Id was not set till then.
            // This is because a compactor thread will iterate over the entries &
            // use only those which have OplogID equal to that of Oplog being
            // compacted without taking any lock. A lock is taken only if the
            // entry is a potential candidate.
            // Further the compactor may delete the file as a compactor thread does
            // not require to take any shared/exclusive lock at DiskStoreImpl
            // or Oplog level.
            // It is also assumed that compactor thread will take a lock on both
            // entry as well as DiskID while compacting. In case of synch
            // mode we can
            // safely set OplogID without taking lock on DiskId. But
            // for asynch mode
            // we have to take additional precaution as the asynch
            // writer of previous
            // oplog can interfere with the current oplog.
            id.setOplogId(getOplogId());
            // do the io while holding lock so that switch can set doneAppending
            // Write the data to the opLog for the synch mode
            startPosForSynchOp = writeOpLogBytes(this.crf, async, true);
            // if (this.crf.currSize != startPosForSynchOp) {
            // assert false;
            // }
            this.crf.currSize = temp;
            if (EntryBits.isNeedsValue(userBits)) {
                id.setValueLength(value.getLength());
            } else {
                id.setValueLength(0);
            }
            id.setUserBits(userBits);
            if (logger.isTraceEnabled()) {
                logger.trace("Oplog::basicCreate:Release dByteBuffer with data for Disk ID = {}", id);
            }
            // As such for any put or get operation , a synch is taken
            // on the Entry object in the DiskEntry's Helper functions.
            // Compactor thread will also take a lock on entry object. Therefore
            // we do not require a lock on DiskID, as concurrent access for
            // value will not occur.
            startPosForSynchOp += getOpStateValueOffset();
            if (logger.isTraceEnabled(LogMarker.PERSIST_WRITES)) {
                VersionTag tag = null;
                if (entry.getVersionStamp() != null) {
                    tag = entry.getVersionStamp().asVersionTag();
                }
                logger.trace(LogMarker.PERSIST_WRITES, "basicCreate: id=<{}> key=<{}> valueOffset={} userBits={} valueLen={} valueBytes={} drId={} versionTag={} oplog#{}", abs(id.getKeyId()), entry.getKey(), startPosForSynchOp, userBits, (value != null ? value.getLength() : 0), value.getBytesAsString(), dr.getId(), tag, getOplogId());
            }
            id.setOffsetInOplog(startPosForSynchOp);
            addLive(dr, entry);
            // Size of the current oplog being increased
            // due to 'create' operation. Set the change in stats.
            this.dirHolder.incrementTotalOplogSize(dataLength);
            incTotalCount();
            // Update the region version vector for the disk store.
            // This needs to be done under lock so that we don't switch oplogs
            // unit the version vector accurately represents what is in this oplog
            RegionVersionVector rvv = dr.getRegionVersionVector();
            if (rvv != null && entry.getVersionStamp() != null) {
                rvv.recordVersion(entry.getVersionStamp().getMemberID(), entry.getVersionStamp().getRegionVersion());
            }
            EntryLogger.logPersistPut(dr.getName(), entry.getKey(), dr.getDiskStoreID());
        }
        clearOpState();
    // }
    }
    if (useNextOplog) {
        if (LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER) {
            CacheObserverHolder.getInstance().afterSwitchingOplog();
        }
        Assert.assertTrue(this != getOplogSet().getChild());
        getOplogSet().getChild().basicCreate(dr, entry, value, userBits, async);
    } else {
        if (LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER) {
            CacheObserverHolder.getInstance().afterSettingOplogOffSet(startPosForSynchOp);
        }
    }
}
Also used : VersionTag(org.apache.geode.internal.cache.versions.VersionTag) RegionVersionVector(org.apache.geode.internal.cache.versions.RegionVersionVector) CacheClosedException(org.apache.geode.cache.CacheClosedException)

Example 30 with RegionVersionVector

use of org.apache.geode.internal.cache.versions.RegionVersionVector in project geode by apache.

the class Oplog method okToSkipRegion.

/**
   * Returns true if the drId region has been destroyed or if oplogKeyId preceeds the last clear
   * done on the drId region
   */
private OkToSkipResult okToSkipRegion(DiskRegionView drv, long oplogKeyId, VersionTag tag) {
    long lastClearKeyId = drv.getClearOplogEntryId();
    if (lastClearKeyId != DiskStoreImpl.INVALID_ID) {
        if (logger.isTraceEnabled(LogMarker.PERSIST_RECOVERY)) {
            logger.trace(LogMarker.PERSIST_RECOVERY, "lastClearKeyId={} oplogKeyId={}", lastClearKeyId, oplogKeyId);
        }
        if (lastClearKeyId >= 0) {
            if (oplogKeyId <= lastClearKeyId) {
                if (logger.isTraceEnabled(LogMarker.PERSIST_RECOVERY)) {
                    logger.trace(LogMarker.PERSIST_RECOVERY, "okToSkip because oplogKeyId={} <= lastClearKeyId={} for drId={}", oplogKeyId, lastClearKeyId, drv.getId());
                }
                // @todo add some wraparound logic
                return OkToSkipResult.SKIP_RECORD;
            }
        } else {
            // treat it like an unsigned value (-1 == MAX_UNSIGNED)
            if (oplogKeyId > 0 || oplogKeyId <= lastClearKeyId) {
                // if it is < lastClearKeyId
                if (logger.isTraceEnabled(LogMarker.PERSIST_RECOVERY)) {
                    logger.trace(LogMarker.PERSIST_RECOVERY, "okToSkip because oplogKeyId={} <= lastClearKeyId={} for drId={}", oplogKeyId, lastClearKeyId, drv.getId());
                }
                return OkToSkipResult.SKIP_RECORD;
            }
        }
    }
    RegionVersionVector clearRVV = drv.getClearRVV();
    if (clearRVV != null) {
        if (logger.isTraceEnabled(LogMarker.PERSIST_RECOVERY)) {
            logger.trace(LogMarker.PERSIST_RECOVERY, "clearRVV={} tag={}", clearRVV, tag);
        }
        if (clearRVV.contains(tag.getMemberID(), tag.getRegionVersion())) {
            if (logger.isTraceEnabled(LogMarker.PERSIST_RECOVERY)) {
                logger.trace(LogMarker.PERSIST_RECOVERY, "okToSkip because tag={} <= clearRVV={} for drId={}", tag, clearRVV, drv.getId());
            }
            // because later modifies may use the oplog key id.
            return OkToSkipResult.SKIP_VALUE;
        }
    }
    return OkToSkipResult.DONT_SKIP;
}
Also used : RegionVersionVector(org.apache.geode.internal.cache.versions.RegionVersionVector)

Aggregations

RegionVersionVector (org.apache.geode.internal.cache.versions.RegionVersionVector)52 DiskStoreID (org.apache.geode.internal.cache.persistence.DiskStoreID)19 DistributedTest (org.apache.geode.test.junit.categories.DistributedTest)17 Test (org.junit.Test)17 FlakyTest (org.apache.geode.test.junit.categories.FlakyTest)16 VersionTag (org.apache.geode.internal.cache.versions.VersionTag)15 HeapDataOutputStream (org.apache.geode.internal.HeapDataOutputStream)7 ByteArrayInputStream (java.io.ByteArrayInputStream)6 DataInputStream (java.io.DataInputStream)6 VersionSource (org.apache.geode.internal.cache.versions.VersionSource)6 Cache (org.apache.geode.cache.Cache)5 LocalRegion (org.apache.geode.internal.cache.LocalRegion)5 Host (org.apache.geode.test.dunit.Host)4 VM (org.apache.geode.test.dunit.VM)4 HashMap (java.util.HashMap)3 Map (java.util.Map)3 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)3 CacheClosedException (org.apache.geode.cache.CacheClosedException)3 RegionDestroyedException (org.apache.geode.cache.RegionDestroyedException)3 IOException (java.io.IOException)2