mirror of
https://gitee.com/johng/gf
synced 2026-07-04 04:52:48 +08:00
192 lines
5.3 KiB
Go
192 lines
5.3 KiB
Go
// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
|
||
//
|
||
// This Source Code Form is subject to the terms of the MIT License.
|
||
// If a copy of the MIT was not distributed with this file,
|
||
// You can obtain one at https://gitee.com/johng/gf.
|
||
|
||
// 文件空间管理
|
||
package gfilespace
|
||
|
||
import (
|
||
"sync"
|
||
"gitee.com/johng/gf/g/container/gbtree"
|
||
)
|
||
|
||
// 文件空间管理结构体
|
||
type Space struct {
|
||
mu sync.RWMutex // 并发操作锁
|
||
blocks *gbtree.BTree // 所有的空间块构建的B+树
|
||
sizetr *gbtree.BTree // 空间块大小构建的B+树
|
||
sizemap map[int]*gbtree.BTree // 按照空间块大小构建的索引哈希表,便于检索,每个表项是一个B+树
|
||
}
|
||
|
||
// 文件空闲块
|
||
type Block struct {
|
||
index int // 文件偏移量
|
||
size int // 区块大小(byte)
|
||
}
|
||
|
||
// 用于B+树的接口具体实现定义
|
||
func (block *Block) Less(item gbtree.Item) bool {
|
||
if block.index < item.(*Block).index {
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
// 创建一个空间管理器
|
||
func New() *Space {
|
||
return &Space {
|
||
blocks : gbtree.New(10),
|
||
sizetr : gbtree.New(5),
|
||
sizemap : make(map[int]*gbtree.BTree),
|
||
}
|
||
}
|
||
|
||
// 添加空闲空间到管理器
|
||
func (space *Space) addBlock(index int, size int) {
|
||
block := &Block{index, size}
|
||
|
||
// 插入进全局树
|
||
space.blocks.ReplaceOrInsert(block)
|
||
|
||
// 插入进入索引表
|
||
space.insertIntoSizeMap(block)
|
||
|
||
// 对插入的数据进行合并检测
|
||
space.checkMerge(block)
|
||
}
|
||
|
||
// 获取指定block的前一项block
|
||
func (space *Space) getPrevBlock(block *Block) *Block {
|
||
var pblock *Block = nil
|
||
space.blocks.DescendLessOrEqual(block, func(item gbtree.Item) bool {
|
||
if item.(*Block).index != block.index {
|
||
pblock = item.(*Block)
|
||
return false
|
||
}
|
||
return true
|
||
})
|
||
return pblock
|
||
}
|
||
|
||
// 获取指定block的后一项block
|
||
func (space *Space) getNextBlock(block *Block) *Block {
|
||
var nblock *Block = nil
|
||
space.blocks.AscendGreaterOrEqual(block, func(item gbtree.Item) bool {
|
||
if item.(*Block).index != block.index {
|
||
nblock = item.(*Block)
|
||
return false
|
||
}
|
||
return true
|
||
})
|
||
return nblock
|
||
}
|
||
|
||
// 获取指定block的前一项block size
|
||
func (space *Space) getPrevBlockSize(size int) int {
|
||
psize := 0
|
||
space.sizetr.DescendLessOrEqual(gbtree.Int(size), func(item gbtree.Item) bool {
|
||
if int(item.(gbtree.Int)) != size {
|
||
psize = int(item.(gbtree.Int))
|
||
return false
|
||
}
|
||
return true
|
||
})
|
||
return psize
|
||
}
|
||
|
||
// 获取指定block的后一项block size
|
||
func (space *Space) getNextBlockSize(size int) int {
|
||
nsize := 0
|
||
space.sizetr.AscendGreaterOrEqual(gbtree.Int(size), func(item gbtree.Item) bool {
|
||
if int(item.(gbtree.Int)) != size {
|
||
nsize = int(item.(gbtree.Int))
|
||
return false
|
||
}
|
||
return true
|
||
})
|
||
return nsize
|
||
}
|
||
|
||
// 内部按照索引检查合并
|
||
func (space *Space) checkMerge(block *Block) {
|
||
// 首先检查插入空间块的前一项往后是否可以合并,如果当前合并失败后,才会判断当前插入项和后续的空间块合并
|
||
if b := space.checkMergeOfTwoBlock(space.getPrevBlock(block), block); b.index == block.index {
|
||
// 其次检查插入空间块的当前项往后是否可以合并
|
||
space.checkMergeOfTwoBlock(block, space.getNextBlock(block))
|
||
}
|
||
}
|
||
|
||
// 连续检测两个空间块的合并,返回最后一个无法合并的空间块指针
|
||
func (space *Space) checkMergeOfTwoBlock(pblock, block *Block) *Block {
|
||
if pblock == nil {
|
||
return block
|
||
}
|
||
if block == nil {
|
||
return pblock
|
||
}
|
||
for {
|
||
if pblock.index + int(pblock.size) >= block.index {
|
||
space.removeBlock(block)
|
||
// 判断是否需要更新大小
|
||
if pblock.index + int(pblock.size) < block.index + int(block.size) {
|
||
space.removeFromSizeMap(pblock)
|
||
pblock.size = block.index + block.size - pblock.index
|
||
space.insertIntoSizeMap(pblock)
|
||
}
|
||
block = space.getNextBlock(pblock)
|
||
if block == nil {
|
||
return pblock
|
||
}
|
||
} else {
|
||
break
|
||
}
|
||
}
|
||
return block
|
||
}
|
||
|
||
// 插入空间块到索引表
|
||
func (space *Space) insertIntoSizeMap(block *Block) {
|
||
tree, ok := space.sizemap[block.size]
|
||
if !ok {
|
||
tree = gbtree.New(10)
|
||
space.sizemap[block.size] = tree
|
||
}
|
||
tree.ReplaceOrInsert(block)
|
||
|
||
// 插入空间块大小记录表
|
||
space.sizetr.ReplaceOrInsert(gbtree.Int(block.size))
|
||
}
|
||
|
||
|
||
// 删除一项
|
||
func (space *Space) removeBlock(block *Block) {
|
||
space.blocks.Delete(block)
|
||
space.removeFromSizeMap(block)
|
||
}
|
||
|
||
// 从索引表中删除对应的空间块
|
||
func (space *Space) removeFromSizeMap(block *Block) {
|
||
if tree, ok := space.sizemap[block.size]; ok {
|
||
tree.Delete(block)
|
||
// 数据数据为空,那么删除该项哈希记录
|
||
if tree.Len() == 0 {
|
||
delete(space.sizemap, block.size)
|
||
space.sizetr.Delete(gbtree.Int(block.size))
|
||
}
|
||
}
|
||
}
|
||
|
||
// 获得碎片偏移量
|
||
func (block *Block) Index() int {
|
||
return block.index
|
||
}
|
||
|
||
// 获得碎片大小
|
||
func (block *Block) Size() int {
|
||
return block.size
|
||
}
|
||
|
||
|