locmap

package module
v0.0.0-...-53865c9 Latest Latest
Warning

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

Go to latest
Published: Feb 15, 2016 License: BSD-3-Clause Imports: 9 Imported by: 4

README

ValueLocMap

Development Repository

Experimental: No stable version of this package yet exists; it is still in early development.

Package locmap provides a concurrency-safe data structure that maps keys to value locations. A key is 128 bits and is specified using two uint64s (keyA, keyB). A value location is specified using a blockID, offset, and length triplet. Each mapping is assigned a timestamp and the greatest timestamp wins.

The timestamp usually has some number of the lowest bits in use for state information such as active and inactive entries. For example, the lowest bit might be used as 0 = active, 1 = deletion marker so that deletion events are retained for some time period before being completely removed with Discard. Exactly how many bits are used and what they're used for is outside the scope of the mapping itself.

This implementation essentially uses a tree structure of slices of key to location assignments. When a slice fills up, an additional slice is created and half the data is moved to the new slice and the tree structure grows. If a slice empties, it is merged with its pair in the tree structure and the tree shrinks. The tree is balanced by high bits of the key, and locations are distributed in the slices by the low bits.

There is also a modified form of the data structure called GroupLocMap that expands the primary key of the map to two 128 bit keys and offers a GetGroup method which retrieves all matching items for the first key.

API Documentation
Why Templating?

This is the latest development area for the package.
Eventually a stable version of the package will be established but, for now, all things about this package are subject to change.

Copyright See AUTHORS. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.

Documentation

Overview

Package locmap provides a concurrency-safe data structure that maps keys to value locations. A key is 128 bits and is specified using two uint64s (keyA, keyB). A value location is specified using a blockID, offset, and length triplet. Each mapping is assigned a timestamp and the greatest timestamp wins.

The timestamp usually has some number of the lowest bits in use for state information such as active and inactive entries. For example, the lowest bit might be used as 0 = active, 1 = deletion marker so that deletion events are retained for some time period before being completely removed with Discard. Exactly how many bits are used and what they're used for is outside the scope of the mapping itself.

This implementation essentially uses a tree structure of slices of key to location assignments. When a slice fills up, an additional slice is created and half the data is moved to the new slice and the tree structure grows. If a slice empties, it is merged with its pair in the tree structure and the tree shrinks. The tree is balanced by high bits of the key, and locations are distributed in the slices by the low bits.

There is also a modified form of the data structure called GroupLocMap that expands the primary key of the map to two 128 bit keys and offers a GetGroup method which retrieves all matching items for the first key.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type GroupLocMap

type GroupLocMap interface {
	// Get returns timestamp, blockID, offset, length for keyA, keyB, childKeyA, childKeyB.
	Get(keyA uint64, keyB uint64, childKeyA uint64, childKeyB uint64) (timestamp uint64, blockID uint32, offset uint32, length uint32)

	// GetGroup returns all items that match keyA, keyB.
	GetGroup(keyA uint64, keyB uint64) []*GroupLocMapItem

	// Set stores timestamp, blockID, offset, length for keyA, keyB and returns
	// the previous timestamp stored. If a newer item is already stored for
	// keyA, keyB, that newer item is kept. If an item with the same timestamp
	// is already stored, it is usually kept unless evenIfSameTimestamp is set
	// true, in which case the passed in data is kept (useful to update a
	// location that moved from memory to disk, for example). Setting an item
	// to blockID == 0 removes it from the mapping if the timestamp stored is
	// less than (or equal to if evenIfSameTimestamp) the timestamp passed in.
	Set(keyA uint64, keyB uint64, childKeyA uint64, childKeyB uint64, timestamp uint64, blockID uint32, offset uint32, length uint32, evenIfSameTimestamp bool) (previousTimestamp uint64)
	// Discard removes any items in the start:stop (inclusive) range whose
	// timestamp & mask != 0.
	Discard(start uint64, stop uint64, mask uint64)
	// ScanCallback calls the callback for each item within the start:stop
	// range (inclusive) whose timestamp & mask != 0 || mask == 0, timestamp &
	// notMask == 0, and timestamp <= cutoff, up to max times; it will return
	// the keyA value the scan stopped and more will be true if there are
	// possibly more items but max was reached.
	//
	// Note that callbacks may have been made with keys that were greater than
	// or equal to where the scan indicated it had stopped (reached the max).
	// This is because the callbacks are made as items are encountered while
	// walking the structure and the structure is not 100% in key order. The
	// items are grouped and the groups are in key order, but the items in each
	// group are not. The max, if reached, will likely be reached in the middle
	// of a group. This means that items may be duplicated in a subsequent scan
	// that begins where a previous scan indicated it stopped.
	//
	// In practice with the valuestore use case this hasn't been an issue yet.
	// Discard passes don't duplicate because the same keys won't match the
	// modified mask from the previous pass. Outgoing pull replication passes
	// just end up with some additional keys placed in the bloom filter
	// resulting in slightly higher false positive rates (corrected for with
	// subsequent iterations). Outgoing push replication passes end up sending
	// duplicate information, wasting a bit of bandwidth.
	//
	// Additionally, the callback itself may abort the scan early by returning
	// false, in which case the (stopped, more) return values are not
	// particularly useful.
	ScanCallback(start uint64, stop uint64, mask uint64, notMask uint64, cutoff uint64, max uint64, callback func(keyA uint64, keyB uint64, childKeyA uint64, childKeyB uint64, timestamp uint64, length uint32) bool) (stopped uint64, more bool)
	// SetInactiveMask defines the mask to use with a timestamp to determine if
	// a location is inactive (deleted, locally removed, etc.) and is used by
	// Stats to determine what to count for its ActiveCount and ActiveBytes.
	SetInactiveMask(mask uint64)
	// Stats returns a Stats instance giving information about the GroupLocMap.
	//
	// Note that this walks the entire data structure and is relatively
	// expensive; debug = true will make it even more expensive.
	//
	// The various values reported when debug=true are left undocumented
	// because they are subject to change based on implementation. They are
	// only provided when stats.String() is called.
	Stats(debug bool) *GroupLocMapStats
	// Clear discards all items from the GroupLocMap.
	Clear()
}

GroupLocMap is an interface for tracking the mappings from keys to the locations of their values.

func NewGroupLocMap

func NewGroupLocMap(c *GroupLocMapConfig) GroupLocMap

NewGroupLocMap returns a new GroupLocMap instance using the config options given.

type GroupLocMapConfig

type GroupLocMapConfig struct {
	// Workers indicates how many workers may be in use (for calculating the
	// number of locks to create, for example). Note that the GroupLocMap does
	// not create any goroutines itself, but is written to allow concurrent
	// access. Defaults to GOMAXPROCS.
	Workers int
	// Roots indicates how many top level nodes the map should have. More top
	// level nodes means less contention but a bit more memory. Defaults to the
	// Workers value squared. This will be rounded up to the next power of two.
	// The floor for this setting is 2.
	Roots int
	// PageSize controls the size in bytes of each chunk of memory allocated.
	// Defaults to 1,048,576 bytes. The floor for this setting is four times
	// the Sizeof an internal entry (160 bytes for ValueLocMap and 224 bytes
	// for GroupLocMap).
	PageSize int
	// SplitMultiplier indicates how full a memory page can get before being
	// split into two pages. Defaults to 3.0, which means 3 times as many
	// entries as the page alone has slots (overflow subpages are used on
	// collisions).
	SplitMultiplier float64
}

GroupLocMapConfig represents the set of values for configuring a GroupLocMap. Note that changing the values in this structure will have no effect on existing GroupLocMaps; they are copied on instance creation.

type GroupLocMapItem

type GroupLocMapItem struct {
	ChildKeyA uint64
	ChildKeyB uint64
	Timestamp uint64
	BlockID   uint32
	Offset    uint32
	Length    uint32
}

type GroupLocMapStats

type GroupLocMapStats struct {
	// ActiveCount is the number of locations whose timestamp & inactiveMask ==
	// 0 as given when Stats() was called.
	ActiveCount uint64
	// ActiveBytes is the number of bytes represented by locations whose
	// timestamp & inactiveMask == 0 as given when Stats() was called.
	ActiveBytes uint64
	// contains filtered or unexported fields
}

func (*GroupLocMapStats) String

func (s *GroupLocMapStats) String() string

type ValueLocMap

type ValueLocMap interface {
	// Get returns timestamp, blockID, offset, length for keyA, keyB.
	Get(keyA uint64, keyB uint64) (timestamp uint64, blockID uint32, offset uint32, length uint32)

	// Set stores timestamp, blockID, offset, length for keyA, keyB and returns
	// the previous timestamp stored. If a newer item is already stored for
	// keyA, keyB, that newer item is kept. If an item with the same timestamp
	// is already stored, it is usually kept unless evenIfSameTimestamp is set
	// true, in which case the passed in data is kept (useful to update a
	// location that moved from memory to disk, for example). Setting an item
	// to blockID == 0 removes it from the mapping if the timestamp stored is
	// less than (or equal to if evenIfSameTimestamp) the timestamp passed in.
	Set(keyA uint64, keyB uint64, timestamp uint64, blockID uint32, offset uint32, length uint32, evenIfSameTimestamp bool) (previousTimestamp uint64)
	// Discard removes any items in the start:stop (inclusive) range whose
	// timestamp & mask != 0.
	Discard(start uint64, stop uint64, mask uint64)
	// ScanCallback calls the callback for each item within the start:stop
	// range (inclusive) whose timestamp & mask != 0 || mask == 0, timestamp &
	// notMask == 0, and timestamp <= cutoff, up to max times; it will return
	// the keyA value the scan stopped and more will be true if there are
	// possibly more items but max was reached.
	//
	// Note that callbacks may have been made with keys that were greater than
	// or equal to where the scan indicated it had stopped (reached the max).
	// This is because the callbacks are made as items are encountered while
	// walking the structure and the structure is not 100% in key order. The
	// items are grouped and the groups are in key order, but the items in each
	// group are not. The max, if reached, will likely be reached in the middle
	// of a group. This means that items may be duplicated in a subsequent scan
	// that begins where a previous scan indicated it stopped.
	//
	// In practice with the valuestore use case this hasn't been an issue yet.
	// Discard passes don't duplicate because the same keys won't match the
	// modified mask from the previous pass. Outgoing pull replication passes
	// just end up with some additional keys placed in the bloom filter
	// resulting in slightly higher false positive rates (corrected for with
	// subsequent iterations). Outgoing push replication passes end up sending
	// duplicate information, wasting a bit of bandwidth.
	//
	// Additionally, the callback itself may abort the scan early by returning
	// false, in which case the (stopped, more) return values are not
	// particularly useful.
	ScanCallback(start uint64, stop uint64, mask uint64, notMask uint64, cutoff uint64, max uint64, callback func(keyA uint64, keyB uint64, timestamp uint64, length uint32) bool) (stopped uint64, more bool)
	// SetInactiveMask defines the mask to use with a timestamp to determine if
	// a location is inactive (deleted, locally removed, etc.) and is used by
	// Stats to determine what to count for its ActiveCount and ActiveBytes.
	SetInactiveMask(mask uint64)
	// Stats returns a Stats instance giving information about the ValueLocMap.
	//
	// Note that this walks the entire data structure and is relatively
	// expensive; debug = true will make it even more expensive.
	//
	// The various values reported when debug=true are left undocumented
	// because they are subject to change based on implementation. They are
	// only provided when stats.String() is called.
	Stats(debug bool) *ValueLocMapStats
	// Clear discards all items from the ValueLocMap.
	Clear()
}

ValueLocMap is an interface for tracking the mappings from keys to the locations of their values.

func NewValueLocMap

func NewValueLocMap(c *ValueLocMapConfig) ValueLocMap

NewValueLocMap returns a new ValueLocMap instance using the config options given.

type ValueLocMapConfig

type ValueLocMapConfig struct {
	// Workers indicates how many workers may be in use (for calculating the
	// number of locks to create, for example). Note that the ValueLocMap does
	// not create any goroutines itself, but is written to allow concurrent
	// access. Defaults to GOMAXPROCS.
	Workers int
	// Roots indicates how many top level nodes the map should have. More top
	// level nodes means less contention but a bit more memory. Defaults to the
	// Workers value squared. This will be rounded up to the next power of two.
	// The floor for this setting is 2.
	Roots int
	// PageSize controls the size in bytes of each chunk of memory allocated.
	// Defaults to 1,048,576 bytes. The floor for this setting is four times
	// the Sizeof an internal entry (160 bytes for ValueLocMap and 224 bytes
	// for GroupLocMap).
	PageSize int
	// SplitMultiplier indicates how full a memory page can get before being
	// split into two pages. Defaults to 3.0, which means 3 times as many
	// entries as the page alone has slots (overflow subpages are used on
	// collisions).
	SplitMultiplier float64
}

ValueLocMapConfig represents the set of values for configuring a ValueLocMap. Note that changing the values in this structure will have no effect on existing ValueLocMaps; they are copied on instance creation.

type ValueLocMapStats

type ValueLocMapStats struct {
	// ActiveCount is the number of locations whose timestamp & inactiveMask ==
	// 0 as given when Stats() was called.
	ActiveCount uint64
	// ActiveBytes is the number of bytes represented by locations whose
	// timestamp & inactiveMask == 0 as given when Stats() was called.
	ActiveBytes uint64
	// contains filtered or unexported fields
}

func (*ValueLocMapStats) String

func (s *ValueLocMapStats) String() string

Jump to

Keyboard shortcuts

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