Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion imageserver/httpd/listDirectories.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"bufio"
"fmt"
"net/http"
"net/url"
"text/template"

"github.com/Cloud-Foundations/Dominator/lib/html"
"github.com/Cloud-Foundations/Dominator/lib/image"
Expand Down Expand Up @@ -32,8 +34,20 @@ func (s state) listDirectoriesHandler(w http.ResponseWriter,
fmt.Fprintln(writer, `<table border="1" style="width:100%">`)
tw, _ := html.NewTableWriter(writer, true, "Name", "Owner Group")
for _, directory := range directories {
tw.WriteRow("", "", directory.Name, directory.Metadata.OwnerGroup)
writeDirectory(tw, directory)
}
tw.Close()
fmt.Fprintln(writer, "</body>")
}

func writeDirectory(tw *html.TableWriter, directory image.Directory) {
name := directory.Name
ownerGroup := directory.Metadata.OwnerGroup
tw.WriteRow("", "",
fmt.Sprintf(
"<a href=\"listImages?directoryName=%s\">%s</a>",
url.QueryEscape(name), template.HTMLEscapeString(name),
),
ownerGroup,
)
}
14 changes: 11 additions & 3 deletions imageserver/httpd/listImages.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,17 @@ import (
func (s state) listImagesHandler(w http.ResponseWriter, req *http.Request) {
writer := bufio.NewWriter(w)
defer writer.Flush()
imageNames := s.imageDataBase.ListImages()
verstr.Sort(imageNames)
if req.URL.RawQuery == "output=text" {
query := req.URL.Query()
var imageNames []string
if directoryName := query.Get("directoryName"); directoryName != "" &&
directoryName != "." {
// Output is already sorted.
imageNames = s.imageDataBase.ListImagesInDirectory(directoryName)
} else {
imageNames = s.imageDataBase.ListImages()
verstr.Sort(imageNames)
}
if query.Get("output") == "text" {
for _, name := range imageNames {
fmt.Fprintln(writer, name)
}
Expand Down
17 changes: 17 additions & 0 deletions imageserver/scanner/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type Config struct {
}

type notifiers map[<-chan string]chan<- string

type makeDirectoryNotifiers map[<-chan image.Directory]chan<- image.Directory

type ImageDataBase struct {
Expand All @@ -42,6 +43,7 @@ type ImageDataBase struct {
// Protected by main lock.
directoryMap map[string]image.DirectoryMetadata
imageMap map[string]*imageType // nil: write in progress.
imageNameIndex imageIndex // sorted keys of image names.
addNotifiers notifiers
deleteNotifiers notifiers
mkdirNotifiers makeDirectoryNotifiers
Expand All @@ -64,6 +66,16 @@ type Params struct {
ObjectServer objectserver.FullObjectServer
}

// imageIndex provides exact and prefix lookups over image names.
// Implementations are not safe for concurrent use; callers must hold the
// main lock.
type imageIndex interface {
Add(name string)
Delete(name string)
Get(name string) (string, bool)
GetByPrefix(prefix string) []string
}

func Load(config Config, params Params) (*ImageDataBase, error) {
return loadImageDataBase(config, params)
}
Expand Down Expand Up @@ -187,6 +199,11 @@ func (imdb *ImageDataBase) ListSelectedImages(
return imdb.listImages(request)
}

func (imdb *ImageDataBase) ListImagesInDirectory(
directoryName string) []string {
return imdb.listImagesInDirectory(directoryName)
}

// ListUnreferencedObjects will return a map listing all the objects and their
// corresponding sizes which are not referenced by an image.
// Note that some objects may have been recently added and the referencing image
Expand Down
11 changes: 11 additions & 0 deletions imageserver/scanner/imdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func (imdb *ImageDataBase) addImage(img *image.Image, name string,
if doCleanup {
imdb.Lock()
delete(imdb.imageMap, name)
imdb.imageNameIndex.Delete(name)
imdb.Unlock()
}
}()
Expand Down Expand Up @@ -392,6 +393,7 @@ func (imdb *ImageDataBase) deleteImageAndUpdateUnreferencedObjectsList(
return
}
delete(imdb.imageMap, name)
imdb.imageNameIndex.Delete(name)
imdb.Params.ObjectServer.AdjustRefcounts(false, img)
}

Expand Down Expand Up @@ -612,6 +614,13 @@ func (imdb *ImageDataBase) listImages(
return names
}

func (imdb *ImageDataBase) listImagesInDirectory(
directoryName string) []string {
imdb.RLock()
defer imdb.RUnlock()
return imdb.imageNameIndex.GetByPrefix(directoryName)
}

func (imdb *ImageDataBase) makeDirectory(directory image.Directory,
authInfo *srpc.AuthInformation, userRpc bool) error {
imdb.Lock()
Expand Down Expand Up @@ -743,6 +752,7 @@ func (imdb *ImageDataBase) restoreImageFromArchive(
if doCleanup {
imdb.Lock()
delete(imdb.imageMap, imageArchive.ImageName)
imdb.imageNameIndex.Delete(imageArchive.ImageName)
imdb.Unlock()
}
}()
Expand Down Expand Up @@ -814,6 +824,7 @@ func (imdb *ImageDataBase) writeImage(name string, img *image.Image,
usageEstimate: usageEstimate,
}
imdb.addNotifiers.sendPlain(name, "add", imdb.Logger)
imdb.imageNameIndex.Add(name)
imdb.Unlock()
return imdb.Params.ObjectServer.AdjustRefcounts(true, img)
}
Expand Down
62 changes: 62 additions & 0 deletions imageserver/scanner/index.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package scanner

import (
"slices"
"strings"
)

// sortedImageIndex is an imageIndex backed by a sorted slice of image names.
type sortedImageIndex struct {
index []string // sorted image names only.
}

func newImageSortedIndex() *sortedImageIndex {
return &sortedImageIndex{index: make([]string, 0)}
}

var _ imageIndex = &sortedImageIndex{}

func (s *sortedImageIndex) Add(name string) {
i, found := slices.BinarySearch(s.index, name)
if found {
return
}
s.index = slices.Insert(s.index, i, name)
}

func (s *sortedImageIndex) Delete(name string) {
i, found := slices.BinarySearch(s.index, name)
if !found {
return
}
s.index = slices.Delete(s.index, i, i+1)
}

func (s *sortedImageIndex) GetByPrefix(prefix string) []string {
if !strings.HasSuffix(prefix, "/") {
prefix += "/"
}
start, _ := slices.BinarySearch(s.index, prefix)
if start == len(s.index) || !strings.HasPrefix(s.index[start], prefix) {
return nil
}
relativeEnd, _ := slices.BinarySearchFunc(s.index[start:], prefix,
func(e, t string) int {
if strings.HasPrefix(e, t) {
// Move the search outside of prefix block.
return -1
}
return strings.Compare(e, t)
},
)
end := start + relativeEnd
return slices.Clone(s.index[start:end])
}

func (s *sortedImageIndex) Get(name string) (string, bool) {
i, found := slices.BinarySearch(s.index, name)
if !found {
return "", false
}
return s.index[i], true
}
2 changes: 2 additions & 0 deletions imageserver/scanner/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func loadImageDataBase(config Config, params Params) (*ImageDataBase, error) {
Params: params,
directoryMap: make(map[string]image.DirectoryMetadata),
imageMap: make(map[string]*imageType),
imageNameIndex: newImageSortedIndex(),
addNotifiers: make(notifiers),
deleteNotifiers: make(notifiers),
mkdirNotifiers: make(makeDirectoryNotifiers),
Expand Down Expand Up @@ -200,6 +201,7 @@ func (imdb *ImageDataBase) loadFile(filename string) error {
imdb.Lock()
defer imdb.Unlock()
imdb.imageMap[filename] = imageEntry
imdb.imageNameIndex.Add(filename)
return nil
}

Expand Down