All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.dbms.database.DatabasePageCache Maven / Gradle / Ivy

Go to download

Neo4j kernel is a lightweight, embedded Java database designed to store data structured as graphs rather than tables. For more information, see http://neo4j.org.

There is a newer version: 5.25.1
Show newest version
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.dbms.database;

import org.eclipse.collections.api.set.ImmutableSet;

import java.io.IOException;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;

import org.neo4j.io.pagecache.IOController;
import org.neo4j.io.pagecache.PageCache;
import org.neo4j.io.pagecache.PageCursor;
import org.neo4j.io.pagecache.PagedFile;
import org.neo4j.io.pagecache.buffer.IOBufferFactory;
import org.neo4j.io.pagecache.context.CursorContext;
import org.neo4j.io.pagecache.monitoring.PageFileCounters;
import org.neo4j.io.pagecache.tracing.FileMappedListener;

import static java.util.Objects.requireNonNull;

/**
 * Wrapper around global page cache for an individual database. Abstracts the knowledge that database can have about other databases mapped files
 * by restricting access to files that mapped by other databases.
 * Any lookup or attempts to flush/close page file or cache itself will influence only files that were mapped by particular database over this wrapper.
 * Database specific page cache lifecycle tight to an individual database, and it will be closed as soon as the particular database will be closed.
 */
public class DatabasePageCache implements PageCache
{
    private final PageCache globalPageCache;
    private final CopyOnWriteArrayList databasePagedFiles = new CopyOnWriteArrayList<>();
    private final IOController ioController;
    private final List mappedListeners = new CopyOnWriteArrayList<>();
    private boolean closed;

    public DatabasePageCache( PageCache globalPageCache, IOController ioController )
    {
        this.globalPageCache = requireNonNull( globalPageCache );
        this.ioController = requireNonNull( ioController );
    }

    @Override
    public PagedFile map( Path path, int pageSize, String databaseName,
            ImmutableSet openOptions, IOController ignoredController ) throws IOException
    {
        // no one should call this version of map method with emptyDatabaseName != null,
        // since it is this class that is decorating map calls with the name of the database
        PagedFile pagedFile = globalPageCache.map( path, pageSize, databaseName, openOptions, ioController );
        DatabasePageFile databasePageFile = new DatabasePageFile( pagedFile, databasePagedFiles, mappedListeners );
        databasePagedFiles.add( databasePageFile );
        invokeFileMapListeners( mappedListeners, databasePageFile );
        return databasePageFile;
    }

    @Override
    public Optional getExistingMapping( Path path )
    {
        Path canonicalFile = path.normalize();
        return databasePagedFiles.stream().filter( pagedFile -> pagedFile.path().equals( canonicalFile ) ).findFirst();
    }

    @Override
    public List listExistingMappings()
    {
        return new ArrayList<>( databasePagedFiles );
    }

    @Override
    public void flushAndForce() throws IOException
    {
        for ( PagedFile pagedFile : databasePagedFiles )
        {
            pagedFile.flushAndForce();
        }
    }

    @Override
    public synchronized void close()
    {
        if ( closed )
        {
            throw new IllegalStateException( "Database page cache was already closed" );
        }
        for ( PagedFile pagedFile : databasePagedFiles )
        {
            pagedFile.close();
        }
        databasePagedFiles.clear();
        closed = true;
    }

    @Override
    public int pageSize()
    {
        return globalPageCache.pageSize();
    }

    @Override
    public int pageReservedBytes()
    {
        return globalPageCache.pageReservedBytes();
    }

    @Override
    public long maxCachedPages()
    {
        return globalPageCache.maxCachedPages();
    }

    @Override
    public IOBufferFactory getBufferFactory()
    {
        return globalPageCache.getBufferFactory();
    }

    private static void invokeFileMapListeners( List listeners, DatabasePageFile databasePageFile )
    {
        for ( FileMappedListener mappedListener : listeners )
        {
            mappedListener.fileMapped( databasePageFile );
        }
    }

    private static void invokeFileUnmapListeners( List listeners, DatabasePageFile databasePageFile )
    {
        for ( FileMappedListener mappedListener : listeners )
        {
            mappedListener.fileUnmapped( databasePageFile );
        }
    }

    public void registerFileMappedListener( FileMappedListener mappedListener )
    {
        mappedListeners.add( mappedListener );
    }

    public void unregisterFileMappedListener( FileMappedListener mappedListener )
    {
        mappedListeners.remove( mappedListener );
    }

    private static class DatabasePageFile implements PagedFile
    {
        private final PagedFile delegate;
        private final List databaseFiles;
        private final List mappedListeners;

        DatabasePageFile( PagedFile delegate, List databaseFiles, List mappedListeners )
        {
            this.delegate = delegate;
            this.databaseFiles = databaseFiles;
            this.mappedListeners = mappedListeners;
        }

        @Override
        public PageCursor io( long pageId, int pf_flags, CursorContext context ) throws IOException
        {
            return delegate.io( pageId, pf_flags, context );
        }

        @Override
        public int pageSize()
        {
            return delegate.pageSize();
        }

        @Override
        public long fileSize() throws IOException
        {
            return delegate.fileSize();
        }

        @Override
        public Path path()
        {
            return delegate.path();
        }

        @Override
        public void flushAndForce() throws IOException
        {
            delegate.flushAndForce();
        }

        @Override
        public long getLastPageId() throws IOException
        {
            return delegate.getLastPageId();
        }

        @Override
        public void close()
        {
            invokeFileUnmapListeners( mappedListeners, this );
            delegate.close();
            databaseFiles.remove( this );
        }

        @Override
        public void setDeleteOnClose( boolean deleteOnClose )
        {
            delegate.setDeleteOnClose( deleteOnClose );
        }

        @Override
        public boolean isDeleteOnClose()
        {
            return delegate.isDeleteOnClose();
        }

        @Override
        public String getDatabaseName()
        {
            return delegate.getDatabaseName();
        }

        @Override
        public PageFileCounters pageFileCounters()
        {
            return delegate.pageFileCounters();
        }

        @Override
        public boolean equals( Object o )
        {
            if ( this == o )
            {
                return true;
            }
            if ( o == null || getClass() != o.getClass() )
            {
                return false;
            }
            DatabasePageFile that = (DatabasePageFile) o;
            return delegate.equals( that.delegate );
        }

        @Override
        public int hashCode()
        {
            return Objects.hash( delegate );
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy