wp
This commit is contained in:
@@ -3,12 +3,12 @@ package atree
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"gordenko.dev/dima/qb/bin"
|
||||
"gordenko.dev/dima/qb/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -52,25 +52,12 @@ const (
|
||||
FlagNewRoot byte = 2 // новая страница
|
||||
)
|
||||
|
||||
var (
|
||||
castagnoliTable = crc32.MakeTable(crc32.Castagnoli)
|
||||
)
|
||||
|
||||
func calcChecksum(page []byte) uint32 {
|
||||
return crc32.Checksum(page, castagnoliTable)
|
||||
}
|
||||
|
||||
type PageToWrite struct {
|
||||
PageNo uint32
|
||||
Data []byte
|
||||
IsReused bool
|
||||
}
|
||||
|
||||
type FreeList interface {
|
||||
// використовується в allocPage
|
||||
ReservePage() uint32
|
||||
}
|
||||
|
||||
type _page struct {
|
||||
PageNo uint32
|
||||
Buf []byte
|
||||
@@ -80,7 +67,6 @@ type _page struct {
|
||||
type Atree struct {
|
||||
file *os.File
|
||||
mutex sync.Mutex
|
||||
freelist FreeList
|
||||
allocatedPagesQty uint32
|
||||
pages map[uint32]*_page
|
||||
pageWaits map[uint32][]chan readResult
|
||||
@@ -93,7 +79,6 @@ type Atree struct {
|
||||
type Options struct {
|
||||
Dir string
|
||||
DatabaseName string
|
||||
FreeList FreeList
|
||||
}
|
||||
|
||||
func New(opt Options) (*Atree, error) {
|
||||
@@ -106,9 +91,7 @@ func New(opt Options) (*Atree, error) {
|
||||
if opt.DatabaseName == "" {
|
||||
return nil, errors.New("DatabaseName option is required")
|
||||
}
|
||||
if opt.FreeList == nil {
|
||||
return nil, errors.New("FreeList option is required")
|
||||
}
|
||||
|
||||
// открываю или создаю dbName.data и dbName.index файлы
|
||||
var (
|
||||
fileName = filepath.Join(opt.Dir, opt.DatabaseName+".db")
|
||||
@@ -136,7 +119,6 @@ func New(opt Options) (*Atree, error) {
|
||||
}
|
||||
|
||||
tree := &Atree{
|
||||
freelist: opt.FreeList,
|
||||
file: file,
|
||||
allocatedPagesQty: allocatedPagesQty,
|
||||
pages: make(map[uint32]*_page),
|
||||
@@ -261,7 +243,7 @@ type NotLinkedDataPage struct {
|
||||
|
||||
func (s NotLinkedDataPage) SetPrevPageNo(prevPageNo uint32) {
|
||||
bin.PutUint32(s.Data[prevPageIdx:], prevPageNo)
|
||||
bin.PutUint32(s.Data[crc32Idx:], calcChecksum(s.Data[:crc32Idx]))
|
||||
bin.PutUint32(s.Data[crc32Idx:], util.CalcChecksum(s.Data[:crc32Idx]))
|
||||
}
|
||||
|
||||
type AppendDataPagesReq struct {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"gordenko.dev/dima/qb"
|
||||
"gordenko.dev/dima/qb/bin"
|
||||
"gordenko.dev/dima/qb/util"
|
||||
)
|
||||
|
||||
// fix - додати ID, щоб потім перемістити із тимчасового буфера в pages, або звільнити
|
||||
@@ -362,7 +363,7 @@ func openFile(fileName string, pageSize int) (_ *os.File, _ uint32, err error) {
|
||||
func (s *Atree) verifyCRC(data []byte, pageSize int) error {
|
||||
var (
|
||||
pos = pageSize - 4
|
||||
calculatedCRC = calcChecksum(data[:pos])
|
||||
calculatedCRC = util.CalcChecksum(data[:pos])
|
||||
storedCRC = bin.GetUint32(data[pos:])
|
||||
)
|
||||
if calculatedCRC != storedCRC {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package atree
|
||||
|
||||
import (
|
||||
"hash/crc32"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var page = make([]byte, 4096)
|
||||
var ieeeTable = crc32.MakeTable(crc32.IEEE)
|
||||
|
||||
func BenchmarkCRC32C(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
crc32.Checksum(page, castagnoliTable)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCRC32IEEE(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
crc32.Checksum(page, ieeeTable)
|
||||
}
|
||||
}
|
||||
40
atree/x.go
40
atree/x.go
@@ -1,6 +1,9 @@
|
||||
package atree
|
||||
|
||||
import "gordenko.dev/dima/qb/bin"
|
||||
import (
|
||||
"gordenko.dev/dima/qb/bin"
|
||||
"gordenko.dev/dima/qb/util"
|
||||
)
|
||||
|
||||
const (
|
||||
payloadSize = 24
|
||||
@@ -16,6 +19,7 @@ type DataPage struct {
|
||||
ValuesSize int
|
||||
PageNo uint32
|
||||
IsReused bool
|
||||
Checksum uint32
|
||||
}
|
||||
|
||||
type IndexPage struct {
|
||||
@@ -23,14 +27,15 @@ type IndexPage struct {
|
||||
Data []byte
|
||||
PageNo uint32
|
||||
IsReused bool
|
||||
Checksum uint32
|
||||
}
|
||||
type IndexLevel struct {
|
||||
// вже записані дані (лише для першої в списку індексної сторінки, беремо із _metric)
|
||||
// дані потрібні, якщо сторінка буде заповнена і піде на запис в .index файл
|
||||
Offset int // (заповнені одразу)
|
||||
LowerTimestamp uint32 // (заповнені одразу)
|
||||
Data []byte // поточні дані index сторінки (заповнені одразу)
|
||||
Filled []IndexPage // пусто
|
||||
Offset int // (заповнені одразу)
|
||||
LowerTimestamp uint32 // (заповнені одразу)
|
||||
Data []byte // поточні дані index сторінки (заповнені одразу)
|
||||
Filled []*IndexPage // пусто
|
||||
}
|
||||
|
||||
func appendIndexRecord(data []byte, timestamp uint32, pageNo uint32) []byte {
|
||||
@@ -46,12 +51,13 @@ func appendIndexRecord(data []byte, timestamp uint32, pageNo uint32) []byte {
|
||||
type ChunksToDataPageReq struct {
|
||||
PrevPageNo uint32
|
||||
Timestamps [][]byte // chunks
|
||||
TimestampsSize uint16
|
||||
TimestampsSize int
|
||||
Values [][]byte // chunks
|
||||
ValuesSize uint16
|
||||
ValuesSize int
|
||||
}
|
||||
|
||||
func ChunksToDataPage(buf []byte, req ChunksToDataPageReq) {
|
||||
// return checksum
|
||||
func ChunksToDataPage(buf []byte, req ChunksToDataPageReq) (checksum uint32) {
|
||||
var (
|
||||
remainingSize = int(req.TimestampsSize)
|
||||
pos = 0
|
||||
@@ -80,25 +86,31 @@ func ChunksToDataPage(buf []byte, req ChunksToDataPageReq) {
|
||||
break
|
||||
}
|
||||
}
|
||||
bin.PutUint16(buf[timestampsSizeIdx:], req.TimestampsSize)
|
||||
bin.PutUint16(buf[valuesSizeIdx:], req.ValuesSize)
|
||||
bin.PutUint16(buf[timestampsSizeIdx:], uint16(req.TimestampsSize))
|
||||
bin.PutUint16(buf[valuesSizeIdx:], uint16(req.ValuesSize))
|
||||
bin.PutUint32(buf[prevPageIdx:], req.PrevPageNo)
|
||||
bin.PutUint32(buf[dataCRC32Idx:], calcChecksum(buf[:dataCRC32Idx]))
|
||||
|
||||
checksum = util.CalcChecksum(buf[:dataCRC32Idx])
|
||||
bin.PutUint32(buf[dataCRC32Idx:], checksum)
|
||||
return
|
||||
}
|
||||
|
||||
func DataToIndexPage(buf []byte, data []byte, lastLevel bool) {
|
||||
func DataToIndexPage(buf []byte, data []byte, lastLevel bool) (checksum uint32) {
|
||||
copy(buf, data)
|
||||
bin.PutUint16(buf[indexRecordsQtyIdx:], uint16(len(data)/indexRecordSize))
|
||||
if lastLevel {
|
||||
buf[isLastLevelIdx] = 1
|
||||
}
|
||||
bin.PutUint32(buf[indexCRC32Idx:], calcChecksum(buf[:indexCRC32Idx]))
|
||||
checksum = util.CalcChecksum(buf[:indexCRC32Idx])
|
||||
bin.PutUint32(buf[indexCRC32Idx:], checksum)
|
||||
return
|
||||
}
|
||||
|
||||
type Pager interface {
|
||||
GetPageNumber() (uint32, bool)
|
||||
}
|
||||
|
||||
// fix - reduce leves
|
||||
func AppendDataPagesToTree(pager Pager, levels []*IndexLevel, dataPages []*DataPage) {
|
||||
for i, d := range dataPages[1:] {
|
||||
d.PageNo, d.IsReused = pager.GetPageNumber()
|
||||
@@ -127,7 +139,7 @@ func AppendDataPagesToTree(pager Pager, levels []*IndexLevel, dataPages []*DataP
|
||||
}
|
||||
// в буфері немає місця для додавання нової пари, отже це
|
||||
// заповнена сторінка
|
||||
filled := IndexPage{
|
||||
filled := &IndexPage{
|
||||
LowerTimestamp: level.LowerTimestamp,
|
||||
Data: level.Data,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user