* Copyright 2017, ChαΊΏ VΕ© Gia Hy, cvghy116@gmail.com.
* This file may be used under the terms of the MIT License.
*/
#ifndef EXTENT_ALLOCATOR_H
#define EXTENT_ALLOCATOR_H
#include "BTree.h"
#include "Volume.h"
#include "system_dependencies.h"
#ifdef FS_SHELL
#define ERROR(x...) TRACE(x)
#else
#include <DebugSupport.h>
#endif
#ifdef TRACE_BTRFS
# define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
#else
# define TRACE(x...) ;
#endif
struct CachedExtent : AVLTreeNode {
uint64 offset;
uint64 length;
int refCount;
uint64 flags;
btrfs_extent* item;
static CachedExtent* Create(uint64 offset, uint64 length,
uint64 flags);
void Delete();
uint64 End() const { return offset + length; }
bool IsAllocated() const;
bool IsData() const;
void Info() const;
private:
CachedExtent() {}
CachedExtent(const CachedExtent& other);
};
struct TreeDefinition {
typedef uint64 Key;
typedef CachedExtent Value;
AVLTreeNode* GetAVLTreeNode(Value* value) const
{
return value;
}
Value* GetValue(AVLTreeNode* node) const
{
return static_cast<Value*>(node);
}
int Compare(const Key& a, const Value* b) const
{
if (a < b->offset)
return -1;
if (a >= b->End())
return 1;
return 0;
}
int Compare(const Value* a, const Value* b) const
{
int comp = Compare(a->offset, b);
return comp;
}
};
struct CachedExtentTree : AVLTree<TreeDefinition> {
public:
CachedExtentTree(
const TreeDefinition& definition);
~CachedExtentTree();
status_t FindNext(CachedExtent** chosen, uint64 offset,
uint64 size, uint64 type);
status_t AddExtent(CachedExtent* extent);
status_t FillFreeExtents(uint64 lowerBound,
uint64 upperBound);
void DumpInOrder() const;
void Delete();
private:
status_t _AddAllocatedExtent(CachedExtent* node);
status_t _AddFreeExtent(CachedExtent* node);
void _CombineFreeExtent(CachedExtent* node);
void _RemoveExtent(CachedExtent* node);
void _DumpInOrder(CachedExtent* node) const;
void _Delete(CachedExtent* node);
};
class BlockGroup {
public:
BlockGroup(BTree* extentTree);
~BlockGroup();
status_t SetExtentTree(off_t rootAddress);
status_t Initialize(uint64 flag);
status_t LoadExtent(CachedExtentTree* tree,
bool inverse = false);
uint64 Flags() const { return fItem->Flags(); }
uint64 Start() const { return fKey.ObjectID(); }
uint64 End() const
{ return fKey.ObjectID() + fKey.Offset(); }
private:
BlockGroup(const BlockGroup&);
BlockGroup& operator=(const BlockGroup&);
status_t _InsertExtent(CachedExtentTree* tree,
uint64 size, uint64 length, uint64 flags);
status_t _InsertExtent(CachedExtentTree* tree,
CachedExtent* extent);
private:
btrfs_key fKey;
btrfs_block_group* fItem;
BTree* fCurrentExtentTree;
};
class ExtentAllocator {
public:
ExtentAllocator(Volume* volume);
~ExtentAllocator();
status_t Initialize();
status_t AllocateTreeBlock(uint64& found,
uint64 start = (uint64)-1,
uint64 flags = BTRFS_BLOCKGROUP_FLAG_METADATA);
status_t AllocateDataBlock(uint64& found, uint64 size,
uint64 start = (uint64)-1,
uint64 flags = BTRFS_BLOCKGROUP_FLAG_DATA);
private:
ExtentAllocator(const ExtentAllocator&);
ExtentAllocator& operator=(const ExtentAllocator&);
status_t _LoadExtentTree(uint64 flags);
status_t _Allocate(uint64& found, uint64 start,
uint64 size, uint64 type);
private:
Volume* fVolume;
CachedExtentTree* fTree;
uint64 fStart;
uint64 fEnd;
};
#endif