@@ -37,11 +37,11 @@ import (
3737// chunk reads and minimize the total number of distributed-merge roundtrips.
3838
3939const (
40- minPageSize = max (10 , apc .MinInvNamesPerChunk )
40+ minPageSize = max (10 , apc .MinInvNamesPerChunk ) // 10
4141)
4242
43- // TODO -- FIXME :
44- // - corner case: very small inventory w/ not every target having chunks
43+ // TODO:
44+ // - corner case: very small bucket w/ not every target having inventory LOM
4545// - test list-objects with empty invName (target must resolve single)
4646// - feat: support LsCached (semantics? a) per recorded in chunks or b) w/ respect to local data)
4747// - feat: support listing jobs that currently rely-on/reuse:
@@ -51,21 +51,23 @@ const (
5151// - pagesize default set by proxy (10k when zero) - not optimal for NBI
5252
5353type nbiCtx struct {
54- bck * meta.Bck
55- lom * core.LOM // .sys_inventory/BUCKET-UNAME/INV-NAME
56- ufest * core.Ufest // completed and loaded
57-
58- // runtime state
59- chunkNum int // current chunk number (1-based)
60- nidx int // next index within LsoEntries (limited scope)
61- entries cmn.LsoEntries // decoded from current chunk
62- hdr nbiChunkHdr // current chunk header=[first, last, cnt]
63- prevToken string // responded
64-
65- buf []byte
66- slab * memsys.Slab
67- cksum * cos.CksumHash
68- nat int
54+ lom * core.LOM // .sys_inventory/BUCKET-UNAME/INV-NAME
55+ ufest * core.Ufest // completed and loaded
56+ cksum * cos.CksumHash // chunk header checksum (protection)
57+ slab * memsys.Slab // see (reusable buffer)
58+ bck * meta.Bck // source bucket
59+ prevToken string // responded with prev. nextPage() call
60+ hdr nbiChunkHdr // current chunk header
61+ entries cmn.LsoEntries // decoded from the current chunk
62+ buf []byte // reusable buffer: chunk meta, msgpack
63+ cache struct {
64+ hdr nbiChunkHdr
65+ entries cmn.LsoEntries
66+ chunkNum int
67+ }
68+ nidx int // next index within `entries` (limited scope)
69+ chunkNum int // current chunk number (1-based)
70+ nat int // number of active targets (excepting mainternance mode)
6971}
7072
7173func (nbi * nbiCtx ) init (invName string ) error {
@@ -101,6 +103,9 @@ func (nbi *nbiCtx) init(invName string) error {
101103 return cmn .NewErrNoNodes (apc .Target , smap .CountTargets ())
102104 }
103105
106+ hroom := max (nbi .hdr .entryCount >> 4 , 128 )
107+ nbi .cache .entries = make (cmn.LsoEntries , 0 , nbi .hdr .entryCount + hroom )
108+
104109 return nil
105110}
106111
@@ -137,9 +142,54 @@ func (nbi *nbiCtx) cleanup() {
137142 if nbi .buf != nil && nbi .slab != nil {
138143 nbi .slab .Free (nbi .buf )
139144 }
145+ clear (nbi .entries )
146+ nbi .entries = nbi .entries [:0 ]
147+ clear (nbi .cache .entries )
148+ nbi .cache .entries = nbi .cache .entries [:0 ]
149+ nbi .cache .chunkNum = 0
150+ nbi .cache .hdr = nbiChunkHdr {}
151+ nbi .prevToken = ""
152+ }
153+
154+ func (nbi * nbiCtx ) cacheIt () {
155+ if nbi .chunkNum <= 0 || len (nbi .entries ) == 0 {
156+ debug .Assert (false , "invalid state: " , nbi .chunkNum , " len: " , len (nbi .entries ))
157+ return
158+ }
159+ if nbi .chunkNum >= nbi .ufest .Count () {
160+ return // not caching last (proxy's minToken can only rewind)
161+ }
162+ if nbi .cache .chunkNum == nbi .chunkNum {
163+ return // already cached
164+ }
165+
166+ clear (nbi .cache .entries )
167+ cnt := len (nbi .entries )
168+ if cap (nbi .cache .entries ) < cnt {
169+ nbi .cache .entries = make (cmn.LsoEntries , cnt )
170+ } else {
171+ nbi .cache .entries = nbi .cache .entries [:cnt ]
172+ }
173+ copy (nbi .cache .entries , nbi .entries )
174+ nbi .cache .hdr = nbi .hdr
175+ nbi .cache .chunkNum = nbi .chunkNum
140176}
141177
142178func (nbi * nbiCtx ) readChunk () error {
179+ // cache
180+ if nbi .chunkNum == nbi .cache .chunkNum {
181+ clear (nbi .entries )
182+ cnt := len (nbi .cache .entries )
183+ if cap (nbi .entries ) < cnt {
184+ nbi .entries = make (cmn.LsoEntries , cnt )
185+ } else {
186+ nbi .entries = nbi .entries [:cnt ]
187+ }
188+ copy (nbi .entries , nbi .cache .entries )
189+ nbi .hdr = nbi .cache .hdr
190+ return nil
191+ }
192+
143193 chunk , err := nbi .ufest .GetChunk (nbi .chunkNum )
144194 if err != nil {
145195 return nbi .emit (err )
@@ -205,11 +255,12 @@ func (nbi *nbiCtx) readChunk() error {
205255 return err
206256 }
207257
208- // TODO: remove
258+ // TODO: remove eventually
209259 debug .Assert (len (nbi .entries ) == int (nbi .hdr .entryCount ))
210260 debug .Assert (len (nbi .entries ) > 0 )
211261 debug .Assert (nbi .hdr .first == nbi .entries [0 ].Name )
212262 debug .Assert (nbi .hdr .last == nbi .entries [len (nbi .entries )- 1 ].Name )
263+
213264 return nil
214265}
215266
@@ -271,7 +322,7 @@ func (nbi *nbiCtx) nextPage(msg *apc.LsoMsg, lst *cmn.LsoRes) error {
271322 cp := * e
272323 lst .Entries [i ] = & cp
273324 }
274-
325+ nbi . cacheIt ()
275326 nbi .chunkNum ++
276327 if nbi .chunkNum > nbi .ufest .Count () {
277328 // no more chunks - we are done
@@ -355,6 +406,7 @@ func (nbi *nbiCtx) seekAfter(token string) error {
355406 // token is >= current chunk's last item, move forward until we find
356407 // the first chunk whose range may contain something > token
357408 for {
409+ nbi .cacheIt ()
358410 nbi .chunkNum ++
359411 if nbi .chunkNum > nbi .ufest .Count () {
360412 return nil
0 commit comments