perkeep/server/go/blobserver/enumerate.go

131 lines
2.6 KiB
Go
Raw Normal View History

2010-07-26 03:34:04 +00:00
package main
import (
"camli/blobref"
2010-07-26 03:34:04 +00:00
"fmt"
"http"
2010-07-26 05:18:21 +00:00
"os"
"log"
2010-07-26 05:18:21 +00:00
"sort"
"strconv"
"strings"
2010-07-26 03:34:04 +00:00
)
2010-07-26 05:18:21 +00:00
const maxEnumerate = 100000
type blobInfo struct {
blobref.BlobRef
2010-07-26 05:18:21 +00:00
*os.FileInfo
2010-11-01 23:35:22 +00:00
os.Error
2010-07-26 05:18:21 +00:00
}
func readBlobs(ch chan *blobInfo, blobPrefix, diskRoot, after string, remain *uint) {
dirFullPath := *flagStorageRoot + "/" + diskRoot
dir, err := os.Open(dirFullPath, os.O_RDONLY, 0)
if err != nil {
log.Println("Error opening directory: ", err)
2010-11-01 23:35:22 +00:00
ch <- &blobInfo{Error: err}
2010-07-26 05:18:21 +00:00
return
}
2010-08-03 03:50:54 +00:00
defer dir.Close()
2010-07-26 05:18:21 +00:00
names, err := dir.Readdirnames(32768)
if err != nil {
log.Println("Error reading dirnames: ", err)
2010-11-01 23:35:22 +00:00
ch <- &blobInfo{Error: err}
2010-07-26 05:18:21 +00:00
return
}
sort.SortStrings(names)
for _, name := range names {
if *remain == 0 {
2010-11-01 23:35:22 +00:00
ch <- &blobInfo{Error: os.ENOSPC}
2010-07-26 05:18:21 +00:00
return
}
fullPath := dirFullPath + "/" + name
fi, err := os.Stat(fullPath)
if err != nil {
2010-11-01 23:35:22 +00:00
bi := &blobInfo{Error: err}
2010-07-26 05:18:21 +00:00
ch <- bi
return
}
if fi.IsDirectory() {
var newBlobPrefix string
if blobPrefix == "" {
newBlobPrefix = name + "-"
} else {
newBlobPrefix = blobPrefix + name
}
if len(after) > 0 {
compareLen := len(newBlobPrefix)
if len(after) < compareLen {
compareLen = len(after)
}
if newBlobPrefix[0:compareLen] < after[0:compareLen] {
continue
}
}
readBlobs(ch, newBlobPrefix, diskRoot + "/" + name, after, remain)
continue
}
if fi.IsRegular() && strings.HasSuffix(name, ".dat") {
blobName := name[0:len(name)-4]
if blobName <= after {
continue
}
blobRef := blobref.Parse(blobName)
2010-07-26 05:18:21 +00:00
if blobRef != nil {
bi := &blobInfo{BlobRef: blobRef, FileInfo: fi}
ch <- bi
(*remain)--
}
continue
}
}
if diskRoot == "" {
ch <- nil
}
}
2010-10-04 15:28:14 +00:00
func handleEnumerateBlobs(conn http.ResponseWriter, req *http.Request) {
2010-07-26 05:18:21 +00:00
req.ParseForm()
ch := make(chan *blobInfo, 100)
limit, err := strconv.Atoui(req.FormValue("limit"))
if err != nil || limit > maxEnumerate {
limit = maxEnumerate
}
conn.SetHeader("Content-Type", "text/javascript; charset=utf-8")
fmt.Fprintf(conn, "{\n \"blobs\": [\n")
var after string
go readBlobs(ch, "", "", req.FormValue("after"), &limit);
2010-08-03 03:49:39 +00:00
needsComma := false
2010-07-26 05:18:21 +00:00
for bi := range ch {
if bi == nil {
after = ""
break
}
if bi.Error != nil {
break
}
blobName := bi.BlobRef.String()
2010-08-03 03:49:39 +00:00
if (needsComma) {
fmt.Fprintf(conn, ",\n")
}
fmt.Fprintf(conn, " {\"blobRef\": \"%s\", \"size\": %d}",
2010-07-26 05:18:21 +00:00
blobName, bi.FileInfo.Size)
after = blobName
2010-08-03 03:49:39 +00:00
needsComma = true
2010-07-26 05:18:21 +00:00
}
2010-08-03 03:49:39 +00:00
fmt.Fprintf(conn, "\n ]")
2010-07-26 05:18:21 +00:00
if after != "" {
fmt.Fprintf(conn, ",\n \"after\": \"%s\"", after)
}
fmt.Fprintf(conn, "\n}\n")
2010-07-26 03:34:04 +00:00
}