diff --git a/examples/gettotl/main.go b/examples/gettotl/main.go index e61f071..76f0d15 100644 --- a/examples/gettotl/main.go +++ b/examples/gettotl/main.go @@ -4,6 +4,14 @@ // that can be found in the LICENSE file in the root of the source // tree. +// This example returns the values of a "group" of totl counts/values +// given a 2 uint64 id group tuple. Or it will return the single value +// for a unique 3 uint64 id triple. + +// id1 id2 id3 +// |--group--| +// |--specific id---| + package main import ( @@ -16,8 +24,9 @@ import ( ) func main() { - if len(os.Args) != 5 || os.Args[1] == "-h" { - fmt.Fprintln(os.Stderr, "usage:", os.Args[0], " ") + if (len(os.Args) != 4 && len(os.Args) != 5) || os.Args[1] == "-h" { + fmt.Fprintln(os.Stderr, "usage:", os.Args[0], + " or ") os.Exit(1) } @@ -35,16 +44,33 @@ func main() { if err != nil { log.Fatalln("error parsing id2:", err) } + + if len(os.Args) == 4 { + tg := scoutfs.NewTotalsGroup(f, u1, u2, 10) + for { + ttls, err := tg.Next() + if err != nil { + log.Fatalln("error read totals:", err) + } + if ttls == nil { + break + } + for _, t := range ttls { + fmt.Println("id:", t.ID[2], "xattrs match:", t.Count, "total value:", t.Total) + } + } + return + } + u3, err := strconv.ParseUint(os.Args[4], 10, 64) if err != nil { - log.Fatalln("error parsing id3:", err) + log.Fatalln("error parsing id2:", err) } t, err := scoutfs.ReadXattrTotals(f, u1, u2, u3) if err != nil { - log.Fatalln("error read totals:", err) + log.Fatalln("error reading totals:", err) } - - fmt.Println("xattrs match: ", t.Count) - fmt.Println("total value : ", t.Total) + fmt.Println("Count", t.Count) + fmt.Println("Total", t.Total) } diff --git a/scoutfs.go b/scoutfs.go index 4667adf..453a7f3 100644 --- a/scoutfs.go +++ b/scoutfs.go @@ -12,6 +12,7 @@ import ( "encoding/binary" "fmt" "io" + "math" "os" "path/filepath" "strconv" @@ -870,6 +871,8 @@ type XattrTotal struct { Total uint64 // Count is number of xattrs matching ids Count uint64 + // ID is the id for this total + ID [3]uint64 } // ReadXattrTotals returns the XattrTotal for the given id @@ -895,3 +898,78 @@ func ReadXattrTotals(f *os.File, id1, id2, id3 uint64) (XattrTotal, error) { Count: totls[0].Count, }, nil } + +type TotalsGroup struct { + totls []xattrTotal + pos [3]uint64 + id1 uint64 + id2 uint64 + count int + f *os.File + done bool +} + +// NewTotalsGroup creates a query to get the totals values for a defined +// group of totls (group is defined to match first 2 identifiers). Count +// specifies max number returned for each Next() call. +func NewTotalsGroup(f *os.File, id1, id2 uint64, count int) *TotalsGroup { + totls := make([]xattrTotal, count) + + return &TotalsGroup{ + totls: totls, + f: f, + id1: id1, + id2: id2, + count: count, + pos: [3]uint64{id1, id2, 0}, + } +} + +// Next returns next set of total values for the group +func (t *TotalsGroup) Next() ([]XattrTotal, error) { + if t.done { + return nil, nil + } + + query := readXattrTotals{ + Pos_name: t.pos, + Totals_ptr: uint64(uintptr(unsafe.Pointer(&t.totls[0]))), + Totals_bytes: sizeofxattrTotal * uint64(t.count), + } + + n, err := scoutfsctl(t.f, IOCREADXATTRTOTALS, unsafe.Pointer(&query)) + if err != nil { + return nil, err + } + if n == 0 { + t.done = true + return nil, nil + } + + t.pos = t.totls[n-1].Name + if t.pos[2] == math.MaxUint64 { + t.done = true + } + t.pos[2]++ + + ret := make([]XattrTotal, n) + for i := range ret { + if t.totls[i].Name[0] != t.id1 || t.totls[i].Name[1] != t.id2 { + t.done = true + // id sequence we want is done + return ret[:i], nil + } + ret[i].Count = t.totls[i].Count + ret[i].Total = t.totls[i].Total + ret[i].ID = t.totls[i].Name + } + return ret, nil +} + +// Reset resets the totl query to the start of the group id again +func (t *TotalsGroup) Reset() { + t.done = false + t.pos[0] = t.id1 + t.pos[1] = t.id2 + t.pos[2] = 0 +}