mirror of
https://github.com/anchore/syft.git
synced 2026-11-01 15:06:36 +01:00
chore: simplify and cleanup
Signed-off-by: Keith Zantow <keith.zantow@anchore.com>
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
# internal/index
|
||||
|
||||
A key-split (radix) index over strings, and a forward/reverse pair of them that answers prefix and
|
||||
suffix lookups. Ported from a prototype directory-scan package and kept close to the original so the
|
||||
two can be diffed.
|
||||
|
||||
## Types
|
||||
|
||||
- `KeySplitIndex[T]` / `Node[T]`: a radix tree. Each node holds at most one value and splits its
|
||||
children on the longest common prefix of their keys, so `pom.xml` and `pom.properties` share a
|
||||
`pom.` node. Reads take a read lock per node; writes upgrade to a write lock only where the tree
|
||||
changes. `KeySplitIndex` also marshals to and from a flat JSON object of key → value.
|
||||
- `PrefixSuffix[T]`: two `KeySplitIndex` values, one keyed by the string and one by its reverse, so
|
||||
`ByPrefix("pom")` and `BySuffix(".jar")` are both a single descent followed by a collect.
|
||||
|
||||
## Operations
|
||||
|
||||
| call | answers |
|
||||
|---|---|
|
||||
| `Get(key)` | the value at exactly `key` |
|
||||
| `Set(key, v)` / `Update(key, fn)` | store, or read-modify-write, the value at `key` |
|
||||
| `ByPrefix(p)` | every value whose key starts with `p` |
|
||||
| `BySuffix(s)` (PrefixSuffix only) | every value whose key ends with `s` |
|
||||
|
||||
Values are whatever the caller stores; `internal/archive` stores `[]*node` per base name because a
|
||||
name repeats across directories.
|
||||
|
||||
## Where it is used
|
||||
|
||||
`internal/archive.Index` keeps one `PrefixSuffix[[]*node]` of files by base name. A cataloger glob
|
||||
whose last segment is a literal, `*suffix` or `prefix*` (nearly all of them: `**/*.jar`,
|
||||
`**/pom.properties`) is answered from it instead of by walking every path.
|
||||
|
||||
## Notes
|
||||
|
||||
- Lookups are byte-wise; `reverse` works on runes so a multi-byte name reverses correctly.
|
||||
- `lock.go` returns unlock functions rather than exposing `Unlock`, which is how a node tells a read
|
||||
lock from a write lock when deciding whether to upgrade.
|
||||
- `_find`, `_collect` and `_makeNodeP` are the prototype's internals and are left with its naming.
|
||||
@@ -1,10 +1,5 @@
|
||||
// Package index provides a concurrent key-split (radix) index and a forward/reverse pair over it.
|
||||
//
|
||||
// It answers path queries like "which entries end in .jar" or "live under this directory" as keyed
|
||||
// lookups rather than tree walks, so a cataloger's `**/*.ext` glob need not scan every path.
|
||||
//
|
||||
// Ported from a prototype dir-scan package and kept close to the original for diffing. The lock type
|
||||
// is local (see lock.go) rather than the prototype's, which carries unrelated helpers.
|
||||
// Package index provides a concurrent key-split (radix) index, and a forward/reverse pair over it
|
||||
// that answers prefix and suffix lookups such as "which names end in .jar".
|
||||
package index
|
||||
|
||||
import (
|
||||
@@ -101,41 +96,6 @@ func (n *Node[T]) ByPrefix(s string) []T {
|
||||
return v.Collect()
|
||||
}
|
||||
|
||||
// ByPrefixUpTo returns the values under s, or false once there are more than limit of them. It lets a
|
||||
// caller choosing between two lookups take whichever is selective without paying for the other: a
|
||||
// complete result costs at most limit. The values returned alongside false are partial; discard them.
|
||||
func (n *Node[T]) ByPrefixUpTo(s string, limit int) (values []T, complete bool) {
|
||||
v, _ := n._find(s)
|
||||
if v == nil {
|
||||
return nil, true
|
||||
}
|
||||
return v.CollectUpTo(limit)
|
||||
}
|
||||
|
||||
// CollectUpTo gathers this node's values, giving up as soon as there are more than limit.
|
||||
func (n *Node[T]) CollectUpTo(limit int) (values []T, complete bool) {
|
||||
complete = n._collectUpTo(&values, limit)
|
||||
return values, complete
|
||||
}
|
||||
|
||||
func (n *Node[T]) _collectUpTo(values *[]T, limit int) bool {
|
||||
defer n.RLock()()
|
||||
|
||||
if n.set {
|
||||
if len(*values) >= limit {
|
||||
return false
|
||||
}
|
||||
*values = append(*values, n.value)
|
||||
}
|
||||
|
||||
for _, v := range n.keyMap {
|
||||
if !v._collectUpTo(values, limit) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (n *Node[T]) Update(name string, f NodeUpdateFunc[T]) {
|
||||
unlock := n.Lock()
|
||||
node := n._makeNodeP(&unlock, name, nil)
|
||||
|
||||
@@ -28,16 +28,6 @@ func (f *PrefixSuffix[T]) BySuffix(suffix string) []T {
|
||||
return f.reverseIndex.ByPrefix(reverse(suffix))
|
||||
}
|
||||
|
||||
// ByPrefixUpTo and BySuffixUpTo are the bounded forms, reporting false rather than returning more than
|
||||
// limit values, so a caller can take whichever side is selective without paying for the other.
|
||||
func (f *PrefixSuffix[T]) ByPrefixUpTo(prefix string, limit int) ([]T, bool) {
|
||||
return f.forwardIndex.ByPrefixUpTo(prefix, limit)
|
||||
}
|
||||
|
||||
func (f *PrefixSuffix[T]) BySuffixUpTo(suffix string, limit int) ([]T, bool) {
|
||||
return f.reverseIndex.ByPrefixUpTo(reverse(suffix), limit)
|
||||
}
|
||||
|
||||
func reverse(s string) string {
|
||||
runes := []rune(s)
|
||||
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
|
||||
|
||||
Reference in New Issue
Block a user