root/src/add-ons/kernel/file_systems/bfs/CachedBlock.h
/*
 * Copyright 2001-2020, Axel Dörfler, axeld@pinc-software.de.
 * This file may be used under the terms of the MIT License.
 */
#ifndef CACHED_BLOCK_H
#define CACHED_BLOCK_H


//!     Interface for the block cache


#include "system_dependencies.h"

#include "Volume.h"
#include "Journal.h"
#include "Debug.h"


// The CachedBlock class is completely implemented as inlines.
// It should be used when cache single blocks to make sure they
// will be properly released after use (and it's also very
// convenient to use them).

class CachedBlock {
public:
                                                                CachedBlock(Volume* volume);
                                                                CachedBlock(CachedBlock* cached);
                                                                ~CachedBlock();

        inline  void                            Keep();
        inline  void                            Unset();

        inline status_t                         SetTo(off_t block);
        inline status_t                         SetTo(block_run run);
        inline status_t                         SetToWritable(Transaction& transaction,
                                                                        off_t block, bool empty = false);
        inline status_t                         SetToWritable(Transaction& transaction,
                                                                        block_run run, bool empty = false);
        inline status_t                         MakeWritable(Transaction& transaction);

                        const uint8*            Block() const { return fBlock; }
                        uint8*                          WritableBlock() const { return fBlock; }
                        off_t                           BlockNumber() const { return fBlockNumber; }
                        uint32                          BlockSize() const
                                                                        { return fVolume->BlockSize(); }
                        uint32                          BlockShift() const
                                                                        { return fVolume->BlockShift(); }

private:
        CachedBlock(const CachedBlock& other);
        CachedBlock& operator=(const CachedBlock& other);
                // no implementation

protected:
                        Volume*                         fVolume;
                        off_t                           fBlockNumber;
                        uint8*                          fBlock;
};


// inlines


inline
CachedBlock::CachedBlock(Volume* volume)
        :
        fVolume(volume),
        fBlockNumber(0),
        fBlock(NULL)
{
}


inline
CachedBlock::CachedBlock(CachedBlock* cached)
        :
        fVolume(cached->fVolume),
        fBlockNumber(cached->BlockNumber()),
        fBlock(cached->fBlock)
{
        cached->Keep();
}


inline
CachedBlock::~CachedBlock()
{
        Unset();
}


inline void
CachedBlock::Keep()
{
        fBlock = NULL;
}


inline void
CachedBlock::Unset()
{
        if (fBlock != NULL) {
                block_cache_put(fVolume->BlockCache(), fBlockNumber);
                fBlock = NULL;
        }
}


inline status_t
CachedBlock::SetTo(off_t block)
{
        Unset();
        fBlockNumber = block;
        return block_cache_get_etc(fVolume->BlockCache(), block, (const void**)&fBlock);
}


inline status_t
CachedBlock::SetTo(block_run run)
{
        return SetTo(fVolume->ToBlock(run));
}


inline status_t
CachedBlock::SetToWritable(Transaction& transaction, off_t block, bool empty)
{
        Unset();
        fBlockNumber = block;

        if (empty) {
                fBlock = (uint8*)block_cache_get_empty(fVolume->BlockCache(),
                        block, transaction.ID());
                return fBlock != NULL ? B_OK : B_NO_MEMORY;
        }

        return block_cache_get_writable_etc(fVolume->BlockCache(),
                block, transaction.ID(), (void**)&fBlock);
}


inline status_t
CachedBlock::SetToWritable(Transaction& transaction, block_run run, bool empty)
{
        return SetToWritable(transaction, fVolume->ToBlock(run), empty);
}


inline status_t
CachedBlock::MakeWritable(Transaction& transaction)
{
        if (fBlock == NULL)
                return B_NO_INIT;

        return block_cache_make_writable(fVolume->BlockCache(), fBlockNumber,
                transaction.ID());
}


#endif  // CACHED_BLOCK_H