mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
Document copy-on-write semantics, at all.
The copy-on-write semantics were previously documented only in the 125-line commit log from the patch which introduced them. Add documentation for them in a few likely places.
This commit is contained in:
parent
8397696a59
commit
ecacbf65d4
2 changed files with 38 additions and 1 deletions
|
|
@ -34,6 +34,26 @@ const (
|
|||
// less than 4,096 values, an array is often used. Containers with long runs of
|
||||
// integers would use run length encoding, and more random data usually uses
|
||||
// bitmap encoding.
|
||||
//
|
||||
// The Container type has somewhat magical semantics. Containers can be marked
|
||||
// as "frozen" by the Freeze method, after which, nothing should ever modify
|
||||
// that specific container object again, no matter what. Because of this, but
|
||||
// also sometimes for Even More Esoteric Reasons, *no* container method should
|
||||
// ever be assumed to be genuinely modifying the container it was called on,
|
||||
// and *every* container method that might modify a container should return
|
||||
// the "modified" *Container, which *may point to a different object*. The
|
||||
// caller should always use this resulting container, and if you're storing
|
||||
// a *Container in a data structure, you need to update the data structure's
|
||||
// pointer too.
|
||||
//
|
||||
// A nil *Container is a valid empty container.
|
||||
//
|
||||
// In general, operations on containers which produce new containers *may*
|
||||
// yield new containers, and *may* yield their operands.
|
||||
//
|
||||
// The reason for all of this is to allow containers to have copy-on-write
|
||||
// semantics, which allow us to reduce memory usage dramatically, and GC
|
||||
// load even more dramatically.
|
||||
type Container struct {
|
||||
pointer *uint16 // the data pointer
|
||||
len, cap int32 // length and cap
|
||||
|
|
@ -264,7 +284,9 @@ func (c *Container) setMapped(mapped bool) {
|
|||
// Freeze returns an unmodifiable container identical to c. This might
|
||||
// be c, now marked unmodifiable, or might be a new container. If c
|
||||
// is currently marked as "mapped", referring to a backing store that's
|
||||
// not a conventional Go pointer, the storage may be copied.
|
||||
// not a conventional Go pointer, the storage may (or may not) be copied.
|
||||
// Do not call Freeze on a temporarily-corrupt container, such as one
|
||||
// returned from UnionInPlace but on which you haven't since called Repair.
|
||||
func (c *Container) Freeze() *Container {
|
||||
if c == nil {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -6876,9 +6876,14 @@ func ConvertRunToBitmap(c *Container) *Container {
|
|||
return c.runToBitmap()
|
||||
}
|
||||
|
||||
// Optimize yields a container with the same bits as c, but
|
||||
// adjusted to the smallest-storage type by Roaring rules (thus,
|
||||
// runs where that's smaller, otherwise arrays for N < 4096 and
|
||||
// bitmaps for N >= 4096).
|
||||
func Optimize(c *Container) *Container {
|
||||
return c.optimize()
|
||||
}
|
||||
|
||||
func Union(a, b *Container) (c *Container) {
|
||||
c = union(a, b)
|
||||
// c can be have arrays that are too big, and need
|
||||
|
|
@ -6890,10 +6895,16 @@ func Difference(a, b *Container) *Container {
|
|||
return difference(a, b)
|
||||
}
|
||||
|
||||
// Add yields a container identical to c, but with the given bit set; added
|
||||
// is true if the bit wasn't previously set. It is unspecified whether
|
||||
// the original container is modified.
|
||||
func (c *Container) Add(v uint16) (newC *Container, added bool) {
|
||||
return c.add(v)
|
||||
}
|
||||
|
||||
// Add yields a container identical to c, but with the given bit cleared;
|
||||
// removed is true if the bit was previously set. It is unspecified whether
|
||||
// the original container is modified.
|
||||
func (c *Container) Remove(v uint16) (c2 *Container, removed bool) {
|
||||
return c.remove(v)
|
||||
}
|
||||
|
|
@ -6906,6 +6917,10 @@ func (c *Container) CountRange(start, end int32) (n int32) {
|
|||
return c.countRange(start, end)
|
||||
}
|
||||
|
||||
// UnionInPlace yields a container containing all the bits set in either
|
||||
// c or other. It may, or may not, modify c. The resulting container's
|
||||
// count, as returned by c.N(), may be incorrect; see (*Container).Repair().
|
||||
// Do not freeze a container produced by this operation before repairing it.
|
||||
func (c *Container) UnionInPlace(other *Container) (r *Container) {
|
||||
return c.unionInPlace(other)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue