timeline

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 1, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	CompressMethodGzip uint8 = iota // legacy
	CompressMethodZlib              // default
)

CompressMethod is the way to compress data that record in each chunk timeline. To be conveniently, we use the same compress method for all timelines.

View Source
const DefaultMaxLimit = 7

DefaultMaxLimit is the default maxim time points that a single chunk timeline could have.

Variables

View Source
var (
	DatabaseKeyRoot = []byte("root")

	DatabaseKeyMetadata          = []byte("meta-data")
	DatabaseSubKeyVersion        = []byte("version")
	DatabaseSubKeyCompressMethod = []byte("compress-method")

	DatabaseKeyChunkIndex    = []byte("chunk-index")
	DatabaseSubKeyChunkCount = []byte("chunk-count")
)

These are the key name of the timeline database that we used.

View Source
var DatabaseCurrentVersion = []byte{0, 0, 1}

DatabaseCurrentVersion represents the version of current database. It is not equal to the package version.

Functions

func CompressMethodByBytes added in v0.1.6

func CompressMethodByBytes(compressMethodBytes []byte) uint8

CompressMethodByBytes looks up the compress method id by given compressMethodBytes. panic if compressMethodBytes is broken or the got compress method ID is unknown.

func CompressMethodBytesByID added in v0.1.6

func CompressMethodBytesByID(compressMethod uint8) []byte

CompressMethodBytesByID looks up the bytes represents of given compressMethod. panic when given compress method ID is unknown.

func CompresserFuncByID added in v0.1.6

func CompresserFuncByID(compressMethod uint8) *utils.Compresser

CompresserFuncByID looks up the compresser implements by given compressMethod. panic when given compress method ID is unknown.

Types

type ChunkTimeline

type ChunkTimeline struct {
	// contains filtered or unexported fields
}

ChunkTimeline records the timeline of a chunk, and it contains the change logs about this chunk on this timeline.

In other words, the ChunkTimeline holds the history of this chunk.

Note that it's unsafe for multiple thread to access this struct due to we don't use mutex to ensure the operation is atomic.

So, it's your responsibility to make ensure there is only one thread is using this object.

func (*ChunkTimeline) AllTimePoint

func (s *ChunkTimeline) AllTimePoint() []int64

AllTimePoint returns a slice that holds the unix time of all time points this timeline have. Granted the returned array is non-decreasing. Note that it's unsafe to modify the returned slice.

func (*ChunkTimeline) AllTimePointLen

func (s *ChunkTimeline) AllTimePointLen() int

AllTimePointLen returns the length of the time point that this timeline have.

func (*ChunkTimeline) Append

func (s *ChunkTimeline) Append(
	c *chunk.Chunk, nbts []map[string]any,
	NOPWhenNoChange bool,
) error

Append tries append a new chunk with block NBT data to the timeline of current chunk.

If NOPWhenNoChange is true, then if their is no change between the one that want to append and the latest one, then finally will result in NOP.

Calling Append will make sure there is exist at least one empty space to place the new time point, whether new time point will be added in the end or not.

The way to leave empty space is by calling Pop, and the poped time points must be the most earliest one.

If current timeline is read only, then calling Append will do no operation.

func (*ChunkTimeline) Compact

func (s *ChunkTimeline) Compact() error

Compact compacts the underlying block palette as much as possible, try to delete all unused blocks from it.

If current timeline is empty or read only, then calling Compact will do no operation.

Note that if you got a non-nil from Compact, then the underlying pointer will back to the firest time point due to when an error occurs, some of the underlying data maybe is inconsistent.

Compact is very expensive due to its time complexity is O(C×k×4096×N×L).

  • k is the count of sub chunks that this chunk have.
  • N is the count of time point that this timeline have.
  • L is the average count of layers for each sub chunks in this timeline.
  • C is a little big (bigger than 2) due to there are multiple operations need to do.

func (*ChunkTimeline) Empty

func (s *ChunkTimeline) Empty() bool

Empty returns whether this timeline is empty or not. If is empty, then calling Save will result in no operation.

func (*ChunkTimeline) JumpTo

func (s *ChunkTimeline) JumpTo(index uint) (c *chunk.Chunk, nbts []map[string]any, updateUnixTime int64, err error)

JumpTo moves to a specific time point of this timeline who is in index.

JumpTo is a very useful replacement of Next when you are trying to jump to a specific time point and no need to get the information of other time point.

Note that if JumpTo returned non-nil error, then the underlying pointer will back to the firest time point due to when an error occurs, some of the underlying data maybe is inconsistent.

Time complexity: O(4096×n + C×(d+1)).

  • n is the sub chunk count of this chunk.
  • d is the distance between index and current pointer.
  • C is relevant to the average changes of all these time point.

func (*ChunkTimeline) Last

func (s *ChunkTimeline) Last() (
	c *chunk.Chunk,
	nbts []map[string]any,
	updateUnixTime int64,
	err error,
)

Last gets the latest time point of current chunk and the NBT blocks in it. Time complexity: O(4096×n). n is the sub chunk count of this chunk.

func (*ChunkTimeline) Next

func (s *ChunkTimeline) Next() (
	c *chunk.Chunk, nbts []map[string]any, updateUnixTime int64,
	isLastElement bool, err error,
)

Next gets the next time point of current chunk and the NBT blocks in it.

With the call to Next, we granted that the returned time keeps increasing until the entire time series is traversed.

isLastElement can inform whether the element obtained after the current call to Next is at the end of the time series.

When it is already at the end of the timeline, calling Next again will back to the earliest time point. In other words, Next is self-loop and can be called continuously.

Note that if Next returned non-nil error, then the underlying pointer will back to the firest time point due to when an error occurs, some of the underlying data maybe is inconsistent.

Time complexity: O(4096×n + C). n is the sub chunk count of this chunk. C is relevant to the average changes between last time point and the next one.

func (*ChunkTimeline) Pointer

func (s *ChunkTimeline) Pointer() uint

Pointer returns the index of the next time point that will be read.

func (*ChunkTimeline) Pop

func (s *ChunkTimeline) Pop() error

Pop tries to delete the first time point from this timeline. If current timeline is empty, or it is read only, or there is only one time point, then we will do no operation.

func (*ChunkTimeline) ReadOnly

func (s *ChunkTimeline) ReadOnly() bool

ReadOnly returns whether this timeline is read only or not. If is read only, then calling any function that will modify underlying timeline will result in no operation.

func (*ChunkTimeline) ResetPointer

func (s *ChunkTimeline) ResetPointer()

ResetPointer resets the pointer to the first time point of this timeline. ResetPointer is always successful if there even have no time point.

func (*ChunkTimeline) Save

func (s *ChunkTimeline) Save() error

Save saves current timeline into the underlying database, and also release current timeline.

Read only timeline should also calling Save to release the resource. But read only timeline calling this function will only release but don't do further operation. Additionally, empty non read only timeline is also follow the same behavior. Note that you could use s.Empty() and s.ReadOnly() to check.

If you calling Save and get a nil error, then this timeline is released and can't be used again. Also, you can't call Save multiple times.

But, if Save returned non-nil error, then this object will not released.

Note that we will not check whether it has been released, nor will we check whether you have called Save multiple times.

Save must calling at the last modification of the timeline; otherwise, the timeline will not be able to maintain data consistency.

func (*ChunkTimeline) SetMaxLimit

func (s *ChunkTimeline) SetMaxLimit(maxLimit uint) error

SetMaxLimit sets the timeline could record how many time point. maxLimit must bigger than 0. If less, then set the limit to 1.

After calling SetMaxLimit if overflow immediately, then we will pop some time point from the underlying timeline. Poped time points must be the most earliest one.

Note that calling SetMaxLimit will not change the empty states of this timeline.

If current timeline is read only, then calling SetMaxLimit will do no operation.

type DB

type DB interface {
	DatabaseOperation
	OpenTransaction() (Transaction, error)
	Close() error
}

DB represent to a database that implements some basic funtions.

type DatabaseOperation

type DatabaseOperation interface {
	Delete(key []byte) error
	Get(key []byte) (value []byte)
	Has(key []byte) (has bool)
	Put(key []byte, value []byte) (err error)
}

DatabaseOperation represents some basic operation that a database should be implement.

type InProgressSession

type InProgressSession struct {
	// contains filtered or unexported fields
}

InProgressSession holds the timelines that are still in use.

func NewInProgressSession

func NewInProgressSession() *InProgressSession

NewInProgressSession returns a new InProgressSession

func (*InProgressSession) Require

func (i *InProgressSession) Require(pos define.DimChunk) (releaseFunc func(), success bool)

Require loads a new session which on pos, and ensure there is only one thread is using a timeline from the same chunk.

If there is one thread is using the target timeline, then calling Require will blocking until they finish there using.

Calling releaseFunc to show you release this timeline, and then other thread could start to using them. If you get Require returned false, then that means the underlying database is closed.

type Timeline

type Timeline interface {
	DeleteChunkTimeline(pos define.DimChunk) error
	LoadLatestTimePointUnixTime(pos define.DimChunk) (timeStamp int64)
	NewChunkTimeline(pos define.DimChunk, readOnly bool) (result *ChunkTimeline, err error)
	SaveLatestTimePointUnixTime(pos define.DimChunk, timeStamp int64) error
}

Timeline is the function that timeline database should to implement.

type TimelineDB

type TimelineDB struct {
	DB
	// contains filtered or unexported fields
}

TimelineDB implements chunk timeline and history record provider based on bbolt.

func (*TimelineDB) CloseTimelineDB

func (t *TimelineDB) CloseTimelineDB() error

CloseTimelineDB closes the timeline database. It will wait until all the timelines in use are released before closing the database.

func (*TimelineDB) DeleteChunkTimeline

func (t *TimelineDB) DeleteChunkTimeline(pos define.DimChunk) error

DeleteChunkTimeline deletes the timeline of chunk who at pos. If timeline is not exist, then do no operation.

Time complexity: O(n). n is the time point that this chunk have.

func (*TimelineDB) LoadLatestTimePointUnixTime

func (t *TimelineDB) LoadLatestTimePointUnixTime(pos define.DimChunk) (timeStamp int64)

LoadLatestTimePointUnixTime loads the time when latest time point update. If not exist, then return 0.

func (*TimelineDB) NewChunkTimeline

func (t *TimelineDB) NewChunkTimeline(pos define.DimChunk, readOnly bool) (result *ChunkTimeline, err error)

NewChunkTimeline gets the timeline of a chunk who is at pos.

Note that if timeline of current chunk is not exist, then we will not create a timeline but return an empty one so you can modify it. The time to create the timeline is only when you save a timeline that not empty to the database.

If readOnly is true, then returned a timeline but only can read. For a read only timeline, you also need use ChunkTimeline.Save to release it.

Important:

  • Once any modifications have been made to the returned timeline, you must save them at the end; otherwise, the timeline will not be able to maintain data consistency (only need to save at the last modification).

  • Timeline of one chunk can't be using by multiple threads. Therefore, you will get blocking when a thread calling NewChunkTimeline but there is still some threads are using target chunk.

  • Calling ChunkTimeline.Save to release the timeline.

  • Returned ChunkTimeline can't shared with multiple threads, and it's your responsibility to ensure this thing.

func (*TimelineDB) SaveLatestTimePointUnixTime

func (t *TimelineDB) SaveLatestTimePointUnixTime(pos define.DimChunk, timeStamp int64) error

SaveLatestTimePointUnixTime saves the time when the latest time point is generated. If timeStamp is 0, then delete the time from the database.

func (*TimelineDB) UnderlyingDatabase

func (t *TimelineDB) UnderlyingDatabase() *bbolt.DB

UnderlyingDatabase returns the underlying database of this timeline database. Only should be calling when need iter all timelines for all chunks.

type TimelineDatabase

type TimelineDatabase interface {
	DB
	Timeline
	UnderlyingDatabase() *bbolt.DB
	CloseTimelineDB() error
}

TimelineDatabase wrapper and implements all features from Timeline, and as a provider to provide timeline of chunk related functions.

func Open

func Open(path string, noGrowSync bool, noSync bool) (result TimelineDatabase, err error)

Open open a level database that used for chunk delta update whose at path. If not exist, then create a new database.

When noGrowSync is true, skips the truncate call when growing the database. Setting this to true is only safe on non-ext3/ext4 systems. Skipping truncation avoids preallocation of hard drive space and bypasses a truncate() and fsync() syscall on remapping.

Setting the NoSync flag will cause the database to skip fsync() calls after each commit. This can be useful when bulk loading data into a database and you can restart the bulk load in the event of a system failure or database corruption. Do not set this flag for normal use.

If the package global IgnoreNoSync constant is true, this value is ignored. See the comment on that constant for more details.

THIS IS UNSAFE. PLEASE USE WITH CAUTION.

type Transaction

type Transaction interface {
	DatabaseOperation
	Commit() error
	Discard() error
}

Transaction represents a transaction in database.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL