// Lazy, range-fetched RCPG loading: parse the small front matter (header +// directory), plan the byte ranges a given ParseOptions needs, and fetch only// those — so a topology-only load over a range-capable transport never// transfers the property columns. Most of the CSR-skeleton/working-set// machinery the Rust codec layers on top of this is deliberately deferred;// SectionFetch and the directory planner lock the interface it builds on,// and atoms_lazy.go's block-lazy AtomReader is its first landed slice.package rcpg// SectionFetch is a byte-range provider for lazy RCPG loading: it returns// [offset, offset+length) of an RCPG file. Implementations must return// exactly length bytes or an error. Callers plug in files (io.ReaderAt),// HTTP Range requests, or object-store reads.typeSectionFetchinterface {Fetch(offset, length uint64) ([]byte, error)}// MemoryFetch is a SectionFetch over an in-memory RCPG slice, returning// sub-slices with no copy — the lazy-load equivalent of eager Parse, useful// for embedding and for parity tests of the lazy path.typeMemoryFetch []byte// Fetch implements SectionFetch.func ( MemoryFetch) (, uint64) ([]byte, error) { := + if < || > uint64(len()) {returnnil, corruptf("range %d+%d past end of file (%d)", , , len()) }return [:], nil}// DirEntry is one section directory entry: (id, offset, length) in file// order.typeDirEntrystruct { ID uint32 Offset uint64 Length uint64}// ByteRange is a half-open [Start, End) byte range within a file.typeByteRangestruct { Start uint64 End uint64}// Directory is the RCPG header + section directory — the small, resident// front matter of a file. Parse it from the leading bytes (16-byte header +// section_count x 24-byte entries), then PlanSections to get the byte ranges// a given ParseOptions needs, so the bodies can be range-fetched without// transferring the whole file.typeDirectorystruct { entries []DirEntry}// FrontMatterLen is the number of front-matter bytes (header + directory)// for a file with sectionCount sections — what to fetch before the directory// can be parsed.func ( uint32) uint64 {returnheaderLen + uint64()*dirEntryLen}// SectionCount reads the section count from a header prefix (at least 16// bytes), validating the magic and version. Use with FrontMatterLen to size// the directory fetch.func ( []byte) (uint32, error) { := newCursor() , := .take(4)if != nil {return0, }if [4]byte() != Magic {return0, corruptf("bad magic, not an RCPG file") } , := .u16()if != nil {return0, }// Only v1 exists; reject anything else (including the invalid v0), // matching RRSR's strict != Version check. Widen this to a range when a // v2 layout is actually defined.if != Version {return0, unsupportedVersionf("RCPG", ) }if , := .u16(); != nil { // flagsreturn0, } , := .u32()if != nil {return0, }if > 1024 {return0, corruptf("implausible section count %d", ) }return , nil}// ParseDirectory parses the header + full directory from front (which must// hold at least FrontMatterLen bytes). Body offsets are recorded but not// validated against any file length — the bodies live elsewhere and are// checked when fetched.func ( []byte) (*Directory, error) { , := SectionCount()if != nil {returnnil, } := newCursor()if , := .take(headerLen); != nil {returnnil, } := make([]DirEntry, 0, preallocCap(int()))forrange { , := .u32()if != nil {returnnil, }if , := .u32(); != nil { // reservedreturnnil, } , := .u64()if != nil {returnnil, } , := .u64()if != nil {returnnil, } = append(, DirEntry{ID: , Offset: , Length: }) }return &Directory{entries: }, nil}// Entries returns the directory entries in file order.func ( *Directory) () []DirEntry {return .entries}// PlanSections returns the byte ranges to fetch for opts: the topology// sections always, the property columns only when their option is set.// Unknown sections are skipped. Order follows the directory, so the ranges// are ascending and can be coalesced for batched fetches.func ( *Directory) ( ParseOptions) []ByteRange {var []ByteRangefor , := range .entries {ifsectionWanted(.ID, ) { = append(, ByteRange{Start: .Offset, End: .Offset + .Length}) } }return}// LoadPrefixLen is the smallest prefix length [0, len) that contains every// section needed under opts — fetch this many bytes and ParseLazy over a// MemoryFetch of them to load without the trailing (unwanted) sections.// Because the topology sections precede the property columns in the file, a// topology-only prefix omits the columns entirely; a full load returns the// file length.func ( *Directory) ( ParseOptions) uint64 {varuint64 := falsefor , := range .entries {if !sectionWanted(.ID, ) {continue } = trueif := .Offset + .Length; > { = } }if ! {returnFrontMatterLen(uint32(len(.entries))) }return}// ParseLazy parses an RCPG file through a SectionFetch, transferring only// the sections opts needs. It reads the header, then the directory, then// fetches and decodes each wanted section body — so a topology-only load// over a range-capable transport never transfers the property columns.// Produces a GraphSection identical to ParseWith for the same opts.func ( SectionFetch, ParseOptions) (*GraphSection, error) { , := .Fetch(0, headerLen)if != nil {returnnil, } , := SectionCount()if != nil {returnnil, } , := .Fetch(0, FrontMatterLen())if != nil {returnnil, } , := ParseDirectory()if != nil {returnnil, } := &GraphSection{}for , := range .Entries() {if !sectionWanted(.ID, ) {continue } , := .Fetch(.Offset, .Length)if != nil {returnnil, }ifuint64(len()) != .Length {returnnil, corruptf("section %d fetch returned %d bytes, expected %d", .ID, len(), .Length) }if := decodeSection(.ID, , , ); != nil {returnnil, } }return , nil}
The pages are generated with Goldsv0.8.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.