Add a new generic container registry client via a new `container` package. Use this to create a command line utility as well as a new upload target for container registries. The code uses the github.com/containers/* project and packages to interact with container registires that is also used by skopeo, podman et al. One if the dependencies is `proglottis/gpgme` that is using cgo to bind libgpgme, so we have to add the corresponding devel package to the BuildRequires as well as installing it on CI. Checks will follow later via an integration test.
178 lines
3.6 KiB
Go
178 lines
3.6 KiB
Go
package bbolt
|
|
|
|
import "sort"
|
|
|
|
// hashmapFreeCount returns count of free pages(hashmap version)
|
|
func (f *freelist) hashmapFreeCount() int {
|
|
// use the forwardMap to get the total count
|
|
count := 0
|
|
for _, size := range f.forwardMap {
|
|
count += int(size)
|
|
}
|
|
return count
|
|
}
|
|
|
|
// hashmapAllocate serves the same purpose as arrayAllocate, but use hashmap as backend
|
|
func (f *freelist) hashmapAllocate(txid txid, n int) pgid {
|
|
if n == 0 {
|
|
return 0
|
|
}
|
|
|
|
// if we have a exact size match just return short path
|
|
if bm, ok := f.freemaps[uint64(n)]; ok {
|
|
for pid := range bm {
|
|
// remove the span
|
|
f.delSpan(pid, uint64(n))
|
|
|
|
f.allocs[pid] = txid
|
|
|
|
for i := pgid(0); i < pgid(n); i++ {
|
|
delete(f.cache, pid+i)
|
|
}
|
|
return pid
|
|
}
|
|
}
|
|
|
|
// lookup the map to find larger span
|
|
for size, bm := range f.freemaps {
|
|
if size < uint64(n) {
|
|
continue
|
|
}
|
|
|
|
for pid := range bm {
|
|
// remove the initial
|
|
f.delSpan(pid, size)
|
|
|
|
f.allocs[pid] = txid
|
|
|
|
remain := size - uint64(n)
|
|
|
|
// add remain span
|
|
f.addSpan(pid+pgid(n), remain)
|
|
|
|
for i := pgid(0); i < pgid(n); i++ {
|
|
delete(f.cache, pid+i)
|
|
}
|
|
return pid
|
|
}
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
// hashmapReadIDs reads pgids as input an initial the freelist(hashmap version)
|
|
func (f *freelist) hashmapReadIDs(pgids []pgid) {
|
|
f.init(pgids)
|
|
|
|
// Rebuild the page cache.
|
|
f.reindex()
|
|
}
|
|
|
|
// hashmapGetFreePageIDs returns the sorted free page ids
|
|
func (f *freelist) hashmapGetFreePageIDs() []pgid {
|
|
count := f.free_count()
|
|
if count == 0 {
|
|
return nil
|
|
}
|
|
|
|
m := make([]pgid, 0, count)
|
|
for start, size := range f.forwardMap {
|
|
for i := 0; i < int(size); i++ {
|
|
m = append(m, start+pgid(i))
|
|
}
|
|
}
|
|
sort.Sort(pgids(m))
|
|
|
|
return m
|
|
}
|
|
|
|
// hashmapMergeSpans try to merge list of pages(represented by pgids) with existing spans
|
|
func (f *freelist) hashmapMergeSpans(ids pgids) {
|
|
for _, id := range ids {
|
|
// try to see if we can merge and update
|
|
f.mergeWithExistingSpan(id)
|
|
}
|
|
}
|
|
|
|
// mergeWithExistingSpan merges pid to the existing free spans, try to merge it backward and forward
|
|
func (f *freelist) mergeWithExistingSpan(pid pgid) {
|
|
prev := pid - 1
|
|
next := pid + 1
|
|
|
|
preSize, mergeWithPrev := f.backwardMap[prev]
|
|
nextSize, mergeWithNext := f.forwardMap[next]
|
|
newStart := pid
|
|
newSize := uint64(1)
|
|
|
|
if mergeWithPrev {
|
|
//merge with previous span
|
|
start := prev + 1 - pgid(preSize)
|
|
f.delSpan(start, preSize)
|
|
|
|
newStart -= pgid(preSize)
|
|
newSize += preSize
|
|
}
|
|
|
|
if mergeWithNext {
|
|
// merge with next span
|
|
f.delSpan(next, nextSize)
|
|
newSize += nextSize
|
|
}
|
|
|
|
f.addSpan(newStart, newSize)
|
|
}
|
|
|
|
func (f *freelist) addSpan(start pgid, size uint64) {
|
|
f.backwardMap[start-1+pgid(size)] = size
|
|
f.forwardMap[start] = size
|
|
if _, ok := f.freemaps[size]; !ok {
|
|
f.freemaps[size] = make(map[pgid]struct{})
|
|
}
|
|
|
|
f.freemaps[size][start] = struct{}{}
|
|
}
|
|
|
|
func (f *freelist) delSpan(start pgid, size uint64) {
|
|
delete(f.forwardMap, start)
|
|
delete(f.backwardMap, start+pgid(size-1))
|
|
delete(f.freemaps[size], start)
|
|
if len(f.freemaps[size]) == 0 {
|
|
delete(f.freemaps, size)
|
|
}
|
|
}
|
|
|
|
// initial from pgids using when use hashmap version
|
|
// pgids must be sorted
|
|
func (f *freelist) init(pgids []pgid) {
|
|
if len(pgids) == 0 {
|
|
return
|
|
}
|
|
|
|
size := uint64(1)
|
|
start := pgids[0]
|
|
|
|
if !sort.SliceIsSorted([]pgid(pgids), func(i, j int) bool { return pgids[i] < pgids[j] }) {
|
|
panic("pgids not sorted")
|
|
}
|
|
|
|
f.freemaps = make(map[uint64]pidSet)
|
|
f.forwardMap = make(map[pgid]uint64)
|
|
f.backwardMap = make(map[pgid]uint64)
|
|
|
|
for i := 1; i < len(pgids); i++ {
|
|
// continuous page
|
|
if pgids[i] == pgids[i-1]+1 {
|
|
size++
|
|
} else {
|
|
f.addSpan(start, size)
|
|
|
|
size = 1
|
|
start = pgids[i]
|
|
}
|
|
}
|
|
|
|
// init the tail
|
|
if size != 0 && start != 0 {
|
|
f.addSpan(start, size)
|
|
}
|
|
}
|