X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/ee9d1e39b5d469a827be5a719c9c0860914ab2a8..a9d73c7a0820f4c0997ceaac8143caa0d67e3a65:/sdk/go/arvados/fs_collection.go diff --git a/sdk/go/arvados/fs_collection.go b/sdk/go/arvados/fs_collection.go index 84ff69d6bd..101fade74b 100644 --- a/sdk/go/arvados/fs_collection.go +++ b/sdk/go/arvados/fs_collection.go @@ -457,7 +457,7 @@ func (fs *collectionFileSystem) Sync() error { } func (fs *collectionFileSystem) Flush(path string, shortBlocks bool) error { - node, err := rlookup(fs.fileSystem.root, path) + node, err := rlookup(fs.fileSystem.root, path, nil) if err != nil { return err } @@ -1358,6 +1358,10 @@ func (dn *dirnode) loadManifest(txt string) error { } streams = streams[:len(streams)-1] segments := []storedSegment{} + // streamoffset[n] is the position in the stream of the nth + // block, i.e., ∑ segments[j].size ∀ 0≤j offset { - // Can't continue where we left off. - // TODO: binary search instead of - // rewinding all the way (but this - // situation might be rare anyway) - segIdx, pos = 0, 0 + if segIdx < len(segments) && streamoffset[segIdx] <= offset && streamoffset[segIdx+1] > offset { + // common case with an easy + // optimization: start where the + // previous segment ended + } else if guess := int(offset >> 26); guess >= 0 && guess < len(segments) && streamoffset[guess] <= offset && streamoffset[guess+1] > offset { + // another common case with an easy + // optimization: all blocks are 64 MiB + // (or close enough) + segIdx = guess + } else { + // general case + segIdx = sort.Search(len(segments), func(i int) bool { + return streamoffset[i+1] > offset + }) } for ; segIdx < len(segments); segIdx++ { - seg := segments[segIdx] - next := pos + int64(seg.Len()) - if next <= offset || seg.Len() == 0 { - pos = next - continue - } - if pos >= offset+length { + blkStart := streamoffset[segIdx] + if blkStart >= offset+length { break } + seg := &segments[segIdx] + if seg.size == 0 { + continue + } var blkOff int - if pos < offset { - blkOff = int(offset - pos) + if blkStart < offset { + blkOff = int(offset - blkStart) } - blkLen := seg.Len() - blkOff - if pos+int64(blkOff+blkLen) > offset+length { - blkLen = int(offset + length - pos - int64(blkOff)) + blkLen := seg.size - blkOff + if blkStart+int64(seg.size) > offset+length { + blkLen = int(offset + length - blkStart - int64(blkOff)) } fnode.appendSegment(storedSegment{ kc: dn.fs, @@ -1482,14 +1503,9 @@ func (dn *dirnode) loadManifest(txt string) error { offset: blkOff, length: blkLen, }) - if next > offset+length { - break - } else { - pos = next - } } - if segIdx == len(segments) && pos < offset+length { - return fmt.Errorf("line %d: invalid segment in %d-byte stream: %q", lineno, pos, token) + if segIdx == len(segments) && streamoffset[segIdx] < offset+length { + return fmt.Errorf("line %d: invalid segment in %d-byte stream: %q", lineno, streamoffset[segIdx], token) } } if !anyFileTokens {