Search in sources :

Example 51 with OCacheEntry

use of com.orientechnologies.orient.core.storage.cache.OCacheEntry in project orientdb by orientechnologies.

the class OPaginatedCluster method updateRecord.

public void updateRecord(final long clusterPosition, byte[] content, final int recordVersion, final byte recordType) throws IOException {
    startOperation();
    OSessionStoragePerformanceStatistic statistic = performanceStatisticManager.getSessionPerformanceStatistic();
    if (statistic != null)
        statistic.startRecordUpdateTimer();
    try {
        content = compression.compress(content);
        content = encryption.encrypt(content);
        OAtomicOperation atomicOperation = startAtomicOperation(true);
        acquireExclusiveLock();
        try {
            final OClusterPositionMapBucket.PositionEntry positionEntry = clusterPositionMap.get(clusterPosition, 1);
            if (positionEntry == null) {
                endAtomicOperation(false, null);
                return;
            }
            int nextRecordPosition = positionEntry.getRecordPosition();
            long nextPageIndex = positionEntry.getPageIndex();
            int newRecordPosition = -1;
            long newPageIndex = -1;
            long prevPageIndex = -1;
            int prevRecordPosition = -1;
            long nextEntryPointer = -1;
            int from = 0;
            int to;
            long sizeDiff = 0;
            byte[] updateEntry = null;
            do {
                final int entrySize;
                final int updatedEntryPosition;
                if (updateEntry == null) {
                    if (from == 0) {
                        entrySize = Math.min(getEntryContentLength(content.length), OClusterPage.MAX_RECORD_SIZE);
                        to = entrySize - (2 * OByteSerializer.BYTE_SIZE + OIntegerSerializer.INT_SIZE + OLongSerializer.LONG_SIZE);
                    } else {
                        entrySize = Math.min(content.length - from + OByteSerializer.BYTE_SIZE + OLongSerializer.LONG_SIZE, OClusterPage.MAX_RECORD_SIZE);
                        to = from + entrySize - (OByteSerializer.BYTE_SIZE + OLongSerializer.LONG_SIZE);
                    }
                    updateEntry = new byte[entrySize];
                    int entryPosition = 0;
                    if (from == 0) {
                        updateEntry[entryPosition] = recordType;
                        entryPosition++;
                        OIntegerSerializer.INSTANCE.serializeNative(content.length, updateEntry, entryPosition);
                        entryPosition += OIntegerSerializer.INT_SIZE;
                    }
                    System.arraycopy(content, from, updateEntry, entryPosition, to - from);
                    entryPosition += to - from;
                    if (nextPageIndex == positionEntry.getPageIndex())
                        updateEntry[entryPosition] = 1;
                    entryPosition++;
                    OLongSerializer.INSTANCE.serializeNative(-1, updateEntry, entryPosition);
                    if (to < content.length) {
                        assert entrySize == OClusterPage.MAX_RECORD_SIZE;
                    }
                } else {
                    entrySize = updateEntry.length;
                    if (from == 0) {
                        to = entrySize - (2 * OByteSerializer.BYTE_SIZE + OIntegerSerializer.INT_SIZE + OLongSerializer.LONG_SIZE);
                    } else {
                        to = from + entrySize - (OByteSerializer.BYTE_SIZE + OLongSerializer.LONG_SIZE);
                    }
                }
                int freePageIndex = -1;
                if (nextPageIndex < 0) {
                    FindFreePageResult findFreePageResult = findFreePage(fileId, pinnedStateEntryIndex, entrySize, atomicOperation);
                    nextPageIndex = findFreePageResult.pageIndex;
                    freePageIndex = findFreePageResult.freePageIndex;
                }
                boolean isNew = false;
                OCacheEntry cacheEntry = loadPage(atomicOperation, fileId, nextPageIndex, false);
                if (cacheEntry == null) {
                    cacheEntry = addPage(atomicOperation, fileId);
                    isNew = true;
                }
                cacheEntry.acquireExclusiveLock();
                try {
                    final OClusterPage localPage = new OClusterPage(cacheEntry, isNew, getChanges(atomicOperation, cacheEntry));
                    final int pageFreeSpace = localPage.getFreeSpace();
                    if (freePageIndex < 0)
                        freePageIndex = calculateFreePageIndex(localPage);
                    else
                        assert isNew || freePageIndex == calculateFreePageIndex(localPage);
                    if (nextRecordPosition >= 0) {
                        if (localPage.isDeleted(nextRecordPosition))
                            throw new OPaginatedClusterException("Record with rid " + new ORecordId(id, clusterPosition) + " was deleted", this);
                        int currentEntrySize = localPage.getRecordSize(nextRecordPosition);
                        nextEntryPointer = localPage.getRecordLongValue(nextRecordPosition, currentEntrySize - OLongSerializer.LONG_SIZE);
                        if (currentEntrySize == entrySize) {
                            localPage.replaceRecord(nextRecordPosition, updateEntry, recordVersion);
                            updatedEntryPosition = nextRecordPosition;
                        } else {
                            localPage.deleteRecord(nextRecordPosition);
                            if (localPage.getMaxRecordSize() >= entrySize) {
                                updatedEntryPosition = localPage.appendRecord(recordVersion, updateEntry);
                                if (updatedEntryPosition < 0) {
                                    throw new IllegalStateException("Page " + cacheEntry.getPageIndex() + " does not have enough free space to add record content");
                                }
                            } else {
                                updatedEntryPosition = -1;
                            }
                        }
                        if (nextEntryPointer >= 0) {
                            nextRecordPosition = getRecordPosition(nextEntryPointer);
                            nextPageIndex = getPageIndex(nextEntryPointer);
                        } else {
                            nextPageIndex = -1;
                            nextRecordPosition = -1;
                        }
                    } else {
                        assert localPage.getFreeSpace() >= entrySize;
                        updatedEntryPosition = localPage.appendRecord(recordVersion, updateEntry);
                        if (updatedEntryPosition < 0) {
                            throw new IllegalStateException("Page " + cacheEntry.getPageIndex() + " does not have enough free space to add record content");
                        }
                        nextPageIndex = -1;
                        nextRecordPosition = -1;
                    }
                    sizeDiff += pageFreeSpace - localPage.getFreeSpace();
                } finally {
                    cacheEntry.releaseExclusiveLock();
                    releasePage(atomicOperation, cacheEntry);
                }
                updateFreePagesIndex(fileId, pinnedStateEntryIndex, freePageIndex, cacheEntry.getPageIndex(), atomicOperation);
                if (updatedEntryPosition >= 0) {
                    if (from == 0) {
                        newPageIndex = cacheEntry.getPageIndex();
                        newRecordPosition = updatedEntryPosition;
                    }
                    from = to;
                    if (prevPageIndex >= 0) {
                        OCacheEntry prevCacheEntry = loadPage(atomicOperation, fileId, prevPageIndex, false);
                        prevCacheEntry.acquireExclusiveLock();
                        try {
                            OClusterPage prevPage = new OClusterPage(prevCacheEntry, false, getChanges(atomicOperation, prevCacheEntry));
                            prevPage.setRecordLongValue(prevRecordPosition, -OLongSerializer.LONG_SIZE, createPagePointer(cacheEntry.getPageIndex(), updatedEntryPosition));
                        } finally {
                            prevCacheEntry.releaseExclusiveLock();
                            releasePage(atomicOperation, prevCacheEntry);
                        }
                    }
                    prevPageIndex = cacheEntry.getPageIndex();
                    prevRecordPosition = updatedEntryPosition;
                    updateEntry = null;
                }
            } while (to < content.length || updateEntry != null);
            // clear unneeded pages
            while (nextEntryPointer >= 0) {
                nextPageIndex = getPageIndex(nextEntryPointer);
                nextRecordPosition = getRecordPosition(nextEntryPointer);
                final int freePagesIndex;
                final int freeSpace;
                OCacheEntry cacheEntry = loadPage(atomicOperation, fileId, nextPageIndex, false);
                cacheEntry.acquireExclusiveLock();
                try {
                    final OClusterPage localPage = new OClusterPage(cacheEntry, false, getChanges(atomicOperation, cacheEntry));
                    freeSpace = localPage.getFreeSpace();
                    freePagesIndex = calculateFreePageIndex(localPage);
                    nextEntryPointer = localPage.getRecordLongValue(nextRecordPosition, -OLongSerializer.LONG_SIZE);
                    localPage.deleteRecord(nextRecordPosition);
                    sizeDiff += freeSpace - localPage.getFreeSpace();
                } finally {
                    cacheEntry.releaseExclusiveLock();
                    releasePage(atomicOperation, cacheEntry);
                }
                updateFreePagesIndex(fileId, pinnedStateEntryIndex, freePagesIndex, nextPageIndex, atomicOperation);
            }
            assert newPageIndex >= 0;
            assert newRecordPosition >= 0;
            if (newPageIndex != positionEntry.getPageIndex() || newRecordPosition != positionEntry.getRecordPosition()) {
                clusterPositionMap.update(clusterPosition, new OClusterPositionMapBucket.PositionEntry(newPageIndex, newRecordPosition));
            }
            updateClusterState(fileId, pinnedStateEntryIndex, 0, sizeDiff, atomicOperation);
            addAtomicOperationMetadata(new ORecordId(id, clusterPosition), atomicOperation);
            endAtomicOperation(false, null);
        } catch (RuntimeException e) {
            endAtomicOperation(true, e);
            throw OException.wrapException(new OPaginatedClusterException("Error during record update", this), e);
        } finally {
            releaseExclusiveLock();
        }
    } finally {
        if (statistic != null)
            statistic.stopRecordUpdateTimer();
        completeOperation();
    }
}
Also used : OAtomicOperation(com.orientechnologies.orient.core.storage.impl.local.paginated.atomicoperations.OAtomicOperation) OPaginatedClusterException(com.orientechnologies.orient.core.exception.OPaginatedClusterException) ORecordId(com.orientechnologies.orient.core.id.ORecordId) OCacheEntry(com.orientechnologies.orient.core.storage.cache.OCacheEntry) OSessionStoragePerformanceStatistic(com.orientechnologies.orient.core.storage.impl.local.statistic.OSessionStoragePerformanceStatistic)

Example 52 with OCacheEntry

use of com.orientechnologies.orient.core.storage.cache.OCacheEntry in project orientdb by orientechnologies.

the class OPaginatedCluster method open.

@Override
public void open() throws IOException {
    startOperation();
    try {
        acquireExclusiveLock();
        try {
            final OAtomicOperation atomicOperation = atomicOperationsManager.getCurrentOperation();
            fileId = openFile(atomicOperation, getFullName());
            final OCacheEntry pinnedStateEntry = loadPage(atomicOperation, fileId, 0, false);
            try {
                pinPage(atomicOperation, pinnedStateEntry);
                pinnedStateEntryIndex = pinnedStateEntry.getPageIndex();
            } finally {
                releasePage(atomicOperation, pinnedStateEntry);
            }
            clusterPositionMap.open();
        } finally {
            releaseExclusiveLock();
        }
    } finally {
        completeOperation();
    }
}
Also used : OAtomicOperation(com.orientechnologies.orient.core.storage.impl.local.paginated.atomicoperations.OAtomicOperation) OCacheEntry(com.orientechnologies.orient.core.storage.cache.OCacheEntry)

Example 53 with OCacheEntry

use of com.orientechnologies.orient.core.storage.cache.OCacheEntry in project orientdb by orientechnologies.

the class OPaginatedCluster method initCusterState.

private long initCusterState(long fileId, OAtomicOperation atomicOperation) throws IOException {
    OCacheEntry pinnedStateEntry = addPage(atomicOperation, fileId);
    pinnedStateEntry.acquireExclusiveLock();
    try {
        OPaginatedClusterState paginatedClusterState = new OPaginatedClusterState(pinnedStateEntry, getChanges(atomicOperation, pinnedStateEntry));
        pinPage(atomicOperation, pinnedStateEntry);
        paginatedClusterState.setSize(0);
        paginatedClusterState.setRecordsSize(0);
        for (int i = 0; i < FREE_LIST_SIZE; i++) paginatedClusterState.setFreeListPage(i, -1);
        return pinnedStateEntry.getPageIndex();
    } finally {
        pinnedStateEntry.releaseExclusiveLock();
        releasePage(atomicOperation, pinnedStateEntry);
    }
}
Also used : OCacheEntry(com.orientechnologies.orient.core.storage.cache.OCacheEntry)

Example 54 with OCacheEntry

use of com.orientechnologies.orient.core.storage.cache.OCacheEntry in project orientdb by orientechnologies.

the class OPaginatedCluster method readRecordBuffer.

private ORawBuffer readRecordBuffer(long clusterPosition, int pageCount, OClusterPositionMapBucket.PositionEntry positionEntry) throws IOException {
    final int recordPosition = positionEntry.getRecordPosition();
    final long pageIndex = positionEntry.getPageIndex();
    final OAtomicOperation atomicOperation = atomicOperationsManager.getCurrentOperation();
    if (getFilledUpTo(atomicOperation, fileId) <= pageIndex)
        return null;
    int recordVersion;
    final OCacheEntry cacheEntry = loadPage(atomicOperation, fileId, pageIndex, false, pageCount);
    cacheEntry.acquireSharedLock();
    try {
        final OClusterPage localPage = new OClusterPage(cacheEntry, false, getChanges(atomicOperation, cacheEntry));
        if (localPage.isDeleted(recordPosition))
            return null;
        recordVersion = localPage.getRecordVersion(recordPosition);
    } finally {
        cacheEntry.releaseSharedLock();
        releasePage(atomicOperation, cacheEntry);
    }
    final byte[] fullContent = readFullEntry(clusterPosition, pageIndex, recordPosition, atomicOperation, pageCount);
    if (fullContent == null)
        return null;
    int fullContentPosition = 0;
    final byte recordType = fullContent[fullContentPosition];
    fullContentPosition++;
    final int readContentSize = OIntegerSerializer.INSTANCE.deserializeNative(fullContent, fullContentPosition);
    fullContentPosition += OIntegerSerializer.INT_SIZE;
    byte[] recordContent = compression.uncompress(fullContent, fullContentPosition, readContentSize);
    recordContent = encryption.decrypt(recordContent);
    return new ORawBuffer(recordContent, recordVersion, recordType);
}
Also used : OAtomicOperation(com.orientechnologies.orient.core.storage.impl.local.paginated.atomicoperations.OAtomicOperation) OCacheEntry(com.orientechnologies.orient.core.storage.cache.OCacheEntry)

Example 55 with OCacheEntry

use of com.orientechnologies.orient.core.storage.cache.OCacheEntry in project orientdb by orientechnologies.

the class OPaginatedCluster method updateFreePagesIndex.

private void updateFreePagesIndex(long fileId, long pinnedStateEntryIndex, int prevFreePageIndex, long pageIndex, OAtomicOperation atomicOperation) throws IOException {
    final OCacheEntry cacheEntry = loadPage(atomicOperation, fileId, pageIndex, false);
    cacheEntry.acquireExclusiveLock();
    try {
        final OClusterPage localPage = new OClusterPage(cacheEntry, false, getChanges(atomicOperation, cacheEntry));
        int newFreePageIndex = calculateFreePageIndex(localPage);
        if (prevFreePageIndex == newFreePageIndex)
            return;
        long nextPageIndex = localPage.getNextPage();
        long prevPageIndex = localPage.getPrevPage();
        if (prevPageIndex >= 0) {
            final OCacheEntry prevPageCacheEntry = loadPage(atomicOperation, fileId, prevPageIndex, false);
            prevPageCacheEntry.acquireExclusiveLock();
            try {
                final OClusterPage prevPage = new OClusterPage(prevPageCacheEntry, false, getChanges(atomicOperation, prevPageCacheEntry));
                assert calculateFreePageIndex(prevPage) == prevFreePageIndex;
                prevPage.setNextPage(nextPageIndex);
            } finally {
                prevPageCacheEntry.releaseExclusiveLock();
                releasePage(atomicOperation, prevPageCacheEntry);
            }
        }
        if (nextPageIndex >= 0) {
            final OCacheEntry nextPageCacheEntry = loadPage(atomicOperation, fileId, nextPageIndex, false);
            nextPageCacheEntry.acquireExclusiveLock();
            try {
                final OClusterPage nextPage = new OClusterPage(nextPageCacheEntry, false, getChanges(atomicOperation, nextPageCacheEntry));
                if (calculateFreePageIndex(nextPage) != prevFreePageIndex)
                    calculateFreePageIndex(nextPage);
                assert calculateFreePageIndex(nextPage) == prevFreePageIndex;
                nextPage.setPrevPage(prevPageIndex);
            } finally {
                nextPageCacheEntry.releaseExclusiveLock();
                releasePage(atomicOperation, nextPageCacheEntry);
            }
        }
        localPage.setNextPage(-1);
        localPage.setPrevPage(-1);
        if (prevFreePageIndex < 0 && newFreePageIndex < 0)
            return;
        if (prevFreePageIndex >= 0 && prevFreePageIndex < FREE_LIST_SIZE) {
            if (prevPageIndex < 0)
                updateFreePagesList(fileId, pinnedStateEntryIndex, prevFreePageIndex, nextPageIndex, atomicOperation);
        }
        if (newFreePageIndex >= 0) {
            long oldFreePage;
            OCacheEntry pinnedStateEntry = loadPage(atomicOperation, fileId, pinnedStateEntryIndex, true);
            pinnedStateEntry.acquireSharedLock();
            try {
                OPaginatedClusterState clusterFreeList = new OPaginatedClusterState(pinnedStateEntry, getChanges(atomicOperation, pinnedStateEntry));
                oldFreePage = clusterFreeList.getFreeListPage(newFreePageIndex);
            } finally {
                pinnedStateEntry.releaseSharedLock();
                releasePage(atomicOperation, pinnedStateEntry);
            }
            if (oldFreePage >= 0) {
                final OCacheEntry oldFreePageCacheEntry = loadPage(atomicOperation, fileId, oldFreePage, false);
                oldFreePageCacheEntry.acquireExclusiveLock();
                try {
                    final OClusterPage oldFreeLocalPage = new OClusterPage(oldFreePageCacheEntry, false, getChanges(atomicOperation, oldFreePageCacheEntry));
                    assert calculateFreePageIndex(oldFreeLocalPage) == newFreePageIndex;
                    oldFreeLocalPage.setPrevPage(pageIndex);
                } finally {
                    oldFreePageCacheEntry.releaseExclusiveLock();
                    releasePage(atomicOperation, oldFreePageCacheEntry);
                }
                localPage.setNextPage(oldFreePage);
                localPage.setPrevPage(-1);
            }
            updateFreePagesList(fileId, pinnedStateEntryIndex, newFreePageIndex, pageIndex, atomicOperation);
        }
    } finally {
        cacheEntry.releaseExclusiveLock();
        releasePage(atomicOperation, cacheEntry);
    }
}
Also used : OCacheEntry(com.orientechnologies.orient.core.storage.cache.OCacheEntry)

Aggregations

OCacheEntry (com.orientechnologies.orient.core.storage.cache.OCacheEntry)209 ByteBuffer (java.nio.ByteBuffer)77 OAtomicOperation (com.orientechnologies.orient.core.storage.impl.local.paginated.atomicoperations.OAtomicOperation)76 OLogSequenceNumber (com.orientechnologies.orient.core.storage.impl.local.paginated.wal.OLogSequenceNumber)74 OByteBufferPool (com.orientechnologies.common.directmemory.OByteBufferPool)69 OCachePointer (com.orientechnologies.orient.core.storage.cache.OCachePointer)65 IOException (java.io.IOException)61 OIndexException (com.orientechnologies.orient.core.index.OIndexException)23 OIdentifiable (com.orientechnologies.orient.core.db.record.OIdentifiable)20 OSessionStoragePerformanceStatistic (com.orientechnologies.orient.core.storage.impl.local.statistic.OSessionStoragePerformanceStatistic)20 OWALChangesTree (com.orientechnologies.orient.core.storage.impl.local.paginated.wal.OWALChangesTree)19 OException (com.orientechnologies.common.exception.OException)17 Test (org.testng.annotations.Test)17 ORecordId (com.orientechnologies.orient.core.id.ORecordId)14 OStorageException (com.orientechnologies.orient.core.exception.OStorageException)13 OLocalHashTableException (com.orientechnologies.orient.core.exception.OLocalHashTableException)12 OSBTreeBonsaiLocalException (com.orientechnologies.orient.core.exception.OSBTreeBonsaiLocalException)11 Lock (java.util.concurrent.locks.Lock)11 Random (java.util.Random)9 HashMap (java.util.HashMap)8