Skip to content

Commit 846ee81

Browse files
committed
feat: native bucket inventory (cache)
* simple single-slot chunk cache (cacheIt/readChunk) ----- * tests: - add tiny-pages-large-chunks, zero-page-size, empty-invName cases ----- * part thirty-one, prev. commit: ee7514c Signed-off-by: Alex Aizman <alex.aizman@gmail.com>
1 parent f70ec2c commit 846ee81

2 files changed

Lines changed: 83 additions & 20 deletions

File tree

ais/test/nbi_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,17 @@ func TestListInventoryPrefixPermute(t *testing.T) {
371371
pageSize: 3, namesPerChunk: 6, listPageSize: 0,
372372
invName: "inv-zero-ps",
373373
},
374+
{
375+
name: "tiny-pages-large-chunks",
376+
numA: 60, numM: 80, numZ: 40,
377+
pageSize: 5, namesPerChunk: 100, listPageSize: 2,
378+
invName: "inv-tiny-ps",
379+
},
380+
{
381+
name: "many-chunks-tiny-pages",
382+
numA: 50, numM: 50, numZ: 50,
383+
pageSize: 5, namesPerChunk: 10, listPageSize: 2,
384+
},
374385
}
375386

376387
bck := cliBck

xact/xs/ls_nbi.go

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ import (
3737
// chunk reads and minimize the total number of distributed-merge roundtrips.
3838

3939
const (
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

5353
type 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

7173
func (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

142178
func (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

Comments
 (0)