Documentation
¶
Index ¶
- Constants
- Variables
- func CompressMethodByBytes(compressMethodBytes []byte) uint8
- func CompressMethodBytesByID(compressMethod uint8) []byte
- func CompresserFuncByID(compressMethod uint8) *utils.Compresser
- type ChunkTimeline
- func (s *ChunkTimeline) AllTimePoint() []int64
- func (s *ChunkTimeline) AllTimePointLen() int
- func (s *ChunkTimeline) Append(c *chunk.Chunk, nbts []map[string]any, NOPWhenNoChange bool) error
- func (s *ChunkTimeline) Compact() error
- func (s *ChunkTimeline) Empty() bool
- func (s *ChunkTimeline) JumpTo(index uint) (c *chunk.Chunk, nbts []map[string]any, updateUnixTime int64, err error)
- func (s *ChunkTimeline) Last() (c *chunk.Chunk, nbts []map[string]any, updateUnixTime int64, err error)
- func (s *ChunkTimeline) Next() (c *chunk.Chunk, nbts []map[string]any, updateUnixTime int64, ...)
- func (s *ChunkTimeline) Pointer() uint
- func (s *ChunkTimeline) Pop() error
- func (s *ChunkTimeline) ReadOnly() bool
- func (s *ChunkTimeline) ResetPointer()
- func (s *ChunkTimeline) Save() error
- func (s *ChunkTimeline) SetMaxLimit(maxLimit uint) error
- type DB
- type DatabaseOperation
- type InProgressSession
- type Timeline
- type TimelineDB
- func (t *TimelineDB) CloseTimelineDB() error
- func (t *TimelineDB) DeleteChunkTimeline(pos define.DimChunk) error
- func (t *TimelineDB) LoadLatestTimePointUnixTime(pos define.DimChunk) (timeStamp int64)
- func (t *TimelineDB) NewChunkTimeline(pos define.DimChunk, readOnly bool) (result *ChunkTimeline, err error)
- func (t *TimelineDB) SaveLatestTimePointUnixTime(pos define.DimChunk, timeStamp int64) error
- func (t *TimelineDB) UnderlyingDatabase() *bbolt.DB
- type TimelineDatabase
- type Transaction
Constants ¶
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.
const DefaultMaxLimit = 7
DefaultMaxLimit is the default maxim time points that a single chunk timeline could have.
Variables ¶
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.
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
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
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.