int blockSize = getRecordSize(); if ( blockSize <= 0 ) log.info( "Rebuilding id generator for[" + getStorageFile() + "] ..." ); closeIdGenerator(); createIdGenerator( idFile ); openIdGenerator(); boolean fastRebuild = isOnlyFastIdGeneratorRebuildEnabled( configuration ); long foundHighId = scanForHighId(); setHighId( foundHighId ); if ( !fastRebuild ) defraggedCount = rebuildIdGeneratorSlow( cursor, getRecordsPerPage(), blockSize, foundHighId ); throw new UnderlyingStorageException( "Unable to rebuild id generator " + getStorageFile(), e ); log.info( "[" + getStorageFile() + "] high id=" + getHighId() + " (defragged=" + defraggedCount + ")" ); log.info( getStorageFile() + " rebuild id generator, highId=" + getHighId() + " defragged count=" + defraggedCount ); closeIdGenerator(); openIdGenerator();
/** * Opens the {@link IdGenerator} used by this store. * <p> * Note: This method may be called both while the store has the store file mapped in the * page cache, and while the store file is not mapped. Implementers must therefore * map their own temporary PagedFile for the store file, and do their file IO through that, * if they need to access the data in the store file. */ void openIdGenerator() { idGenerator = idGeneratorFactory.open( idFile, getIdType(), this::scanForHighId, recordFormat.getMaxId() ); }
private void throwOutOfBoundsException( long recordId ) { RECORD record = newRecord(); record.setId( recordId ); long pageId = pageIdForRecord( recordId ); int offset = offsetForId( recordId ); throw new UnderlyingStorageException( buildOutOfBoundsExceptionMessage( record, pageId, offset, recordSize, pagedFile.pageSize(), storageFile.getAbsolutePath() ) ); }
void initialise( boolean createIfNotExists ) { try { checkAndLoadStorage( createIfNotExists ); } catch ( Exception e ) { closeAndThrow( e ); } }
private void createStore( int pageSize ) throws IOException { try ( PagedFile file = pageCache.map( storageFile, pageSize, StandardOpenOption.CREATE ) ) { initialiseNewStoreFile( file ); } checkAndLoadStorage( false ); }
@Override public <EXCEPTION extends Exception> void scanAllRecords( Visitor<RECORD,EXCEPTION> visitor ) throws EXCEPTION { try ( PageCursor cursor = openPageCursorForReading( 0 ) ) { RECORD record = newRecord(); long highId = getHighId(); for ( long id = getNumberOfReservedLowIds(); id < highId; id++ ) { getRecordByCursor( id, record, CHECK, cursor ); if ( record.inUse() ) { visitor.visit( record ); } } } }
IdValidator.assertValidId( getIdType(), id, recordFormat.getMaxId() ); long pageId = pageIdForRecord( id ); int offset = offsetForId( id ); try ( PageCursor cursor = pagedFile.io( pageId, PF_SHARED_WRITE_LOCK ) ) checkForDecodingErrors( cursor, id, NORMAL ); // We don't free ids if something weird goes wrong if ( !record.inUse() ) freeId( id ); freeId( record.getSecondaryUnitId() );
private void readIntoRecord( long id, RECORD record, RecordLoad mode, PageCursor cursor ) throws IOException { // Mark the record with this id regardless of whether or not we load the contents of it. // This is done in this method since there are multiple call sites and they all want the id // on that record, so it's to ensure it isn't forgotten. record.setId( id ); long pageId = pageIdForRecord( id ); int offset = offsetForId( id ); if ( cursor.next( pageId ) ) { cursor.setOffset( offset ); readRecordFromPage( id, record, mode, cursor ); } else { verifyAfterNotRead( record, mode ); } }
public boolean isInUse( long id ) { long pageId = pageIdForRecord( id ); int offset = offsetForId( id ); try ( PageCursor cursor = pagedFile.io( pageId, PF_SHARED_READ_LOCK ) ) { boolean recordIsInUse = false; if ( cursor.next() ) { cursor.setOffset( offset ); cursor.mark(); do { cursor.setOffsetToMark(); recordIsInUse = isInUse( cursor ); } while ( cursor.shouldRetry() ); checkForDecodingErrors( cursor, id, NORMAL ); } return recordIsInUse; } catch ( IOException e ) { throw new UnderlyingStorageException( e ); } }
public byte[] getRawRecordData( long id ) throws IOException { byte[] data = new byte[recordSize]; long pageId = pageIdForRecord( id ); int offset = offsetForId( id ); try ( PageCursor cursor = pagedFile.io( pageId, PagedFile.PF_SHARED_READ_LOCK ) ) { if ( cursor.next() ) { cursor.setOffset( offset ); cursor.mark(); do { cursor.setOffsetToMark(); cursor.getBytes( data ); } while ( cursor.shouldRetry() ); checkForDecodingErrors( cursor, id, CHECK ); } } return data; }
private static Map<IdType,Long> getHighIds( GraphDatabaseAPI db ) { final Map<IdType,Long> highIds = new HashMap<>(); NeoStores neoStores = db.getDependencyResolver().resolveDependency( RecordStorageEngine.class ).testAccessNeoStores(); Visitor<CommonAbstractStore,RuntimeException> visitor = store -> { highIds.put( store.getIdType(), store.getHighId() ); return true; }; neoStores.visitStore( visitor ); return highIds; }
private void readRecordFromPage( long id, RECORD record, RecordLoad mode, PageCursor cursor ) throws IOException { cursor.mark(); do { prepareForReading( cursor, record ); recordFormat.read( record, cursor, mode, recordSize ); } while ( cursor.shouldRetry() ); checkForDecodingErrors( cursor, id, mode ); verifyAfterReading( record, mode ); }
@Override protected long pageIdForRecord( long id ) { Long override = nextPageId.poll(); return override != null ? override : super.pageIdForRecord( id ); }
/** * If store is not ok a call to this method will rebuild the {@link * IdGenerator} used by this store and if successful mark it as OK. * * WARNING: this method must NOT be called if recovery is required, but hasn't performed. * To remove all negations from the above statement: Only call this method if store is in need of * recovery and recovery has been performed. */ void makeStoreOk() { if ( !storeOk ) { rebuildIdGenerator(); storeOk = true; causeOfStoreNotOk = null; } }
public static long getHighestIdInUseForStore(DependencyResolver dependencyResolver, GlobalOperationsTypes type) { NeoStores neoStores = dependencyResolver.resolveDependency(RecordStorageEngine.class).testAccessNeoStores(); CommonAbstractStore store; switch (type) { case NODES: store = neoStores.getNodeStore(); break; case RELATIONSHIPS: store = neoStores.getRelationshipStore(); break; default: throw new IllegalArgumentException("invalid type " + type); } return store.getHighId(); }
@Override protected int offsetForId( long id ) { Integer override = nextPageOffset.poll(); return override != null ? override : super.offsetForId( id ); } }
/** * Returns the next id for this store's {@link IdGenerator}. * * @return The next free id */ @Override public long nextId() { assertIdGeneratorInitialized(); return idGenerator.nextId(); }
@Override protected void checkAndLoadStorage( boolean createIfNotExists ) { super.checkAndLoadStorage( createIfNotExists ); initHighId(); }
IdValidator.assertValidId( getIdType(), id, recordFormat.getMaxId() ); long pageId = pageIdForRecord( id ); int offset = offsetForId( id ); try ( PageCursor cursor = pagedFile.io( pageId, PF_SHARED_WRITE_LOCK ) ) checkForDecodingErrors( cursor, id, NORMAL ); // We don't free ids if something weird goes wrong if ( !record.inUse() ) freeId( id ); freeId( record.getSecondaryUnitId() );
@Override public <EXCEPTION extends Exception> void scanAllRecords( Visitor<RECORD,EXCEPTION> visitor ) throws EXCEPTION { try ( PageCursor cursor = openPageCursorForReading( 0 ) ) { RECORD record = newRecord(); long highId = getHighId(); for ( long id = getNumberOfReservedLowIds(); id < highId; id++ ) { getRecordByCursor( id, record, CHECK, cursor ); if ( record.inUse() ) { visitor.visit( record ); } } } }