aboutsummaryrefslogtreecommitdiff
path: root/objectstore
diff options
context:
space:
mode:
Diffstat (limited to 'objectstore')
-rw-r--r--objectstore/packed/close.go47
-rw-r--r--objectstore/packed/delta_apply.go136
-rw-r--r--objectstore/packed/delta_build_chain.go (renamed from objectstore/packed/delta_plan.go)40
-rw-r--r--objectstore/packed/delta_cache.go2
-rw-r--r--objectstore/packed/delta_chain.go13
-rw-r--r--objectstore/packed/delta_node.go9
-rw-r--r--objectstore/packed/delta_resolve_chain.go61
-rw-r--r--objectstore/packed/delta_resolve_chain_start.go59
-rw-r--r--objectstore/packed/delta_resolve_content.go29
-rw-r--r--objectstore/packed/delta_size.go27
-rw-r--r--objectstore/packed/entry_meta.go16
-rw-r--r--objectstore/packed/idx.go36
-rw-r--r--objectstore/packed/idx_candidate.go10
-rw-r--r--objectstore/packed/idx_close.go28
-rw-r--r--objectstore/packed/idx_lookup_candidates.go6
-rw-r--r--objectstore/packed/idx_open.go63
-rw-r--r--objectstore/packed/location.go7
-rw-r--r--objectstore/packed/new.go24
-rw-r--r--objectstore/packed/read_closer.go19
-rw-r--r--objectstore/packed/read_reader.go16
-rw-r--r--objectstore/packed/store.go65
-rw-r--r--objectstore/packed/store_open_pack.go43
-rw-r--r--objectstore/packed/trailer_match.go29
23 files changed, 416 insertions, 369 deletions
diff --git a/objectstore/packed/close.go b/objectstore/packed/close.go
new file mode 100644
index 00000000..2bb98232
--- /dev/null
+++ b/objectstore/packed/close.go
@@ -0,0 +1,47 @@
+package packed
+
+// Close releases mapped pack/index resources associated with the store.
+func (store *Store) Close() error {
+ store.stateMu.Lock()
+
+ if store.closed {
+ store.stateMu.Unlock()
+
+ return nil
+ }
+
+ store.closed = true
+ root := store.root
+ packs := store.packs
+ store.stateMu.Unlock()
+ store.idxMu.RLock()
+ indexes := store.idxByPack
+ store.idxMu.RUnlock()
+
+ var closeErr error
+
+ for _, pack := range packs {
+ err := pack.close()
+ if err != nil && closeErr == nil {
+ closeErr = err
+ }
+ }
+
+ for _, index := range indexes {
+ err := index.close()
+ if err != nil && closeErr == nil {
+ closeErr = err
+ }
+ }
+
+ store.cacheMu.Lock()
+ store.deltaCache.clear()
+ store.cacheMu.Unlock()
+
+ err := root.Close()
+ if err != nil && closeErr == nil {
+ closeErr = err
+ }
+
+ return closeErr
+}
diff --git a/objectstore/packed/delta_apply.go b/objectstore/packed/delta_apply.go
deleted file mode 100644
index 71f09ead..00000000
--- a/objectstore/packed/delta_apply.go
+++ /dev/null
@@ -1,136 +0,0 @@
-package packed
-
-import (
- "fmt"
-
- deltaapply "codeberg.org/lindenii/furgit/format/delta/apply"
- packfmt "codeberg.org/lindenii/furgit/format/pack"
- "codeberg.org/lindenii/furgit/objecttype"
-)
-
-// deltaResolveContent resolves one object's content bytes from its pack location.
-func (store *Store) deltaResolveContent(start location) (objecttype.Type, []byte, error) {
- chain, err := store.deltaBuildChain(start)
- if err != nil {
- return objecttype.TypeInvalid, nil, err
- }
-
- pack, meta, err := store.entryMetaAt(start)
- if err != nil {
- return objecttype.TypeInvalid, nil, err
- }
-
- declaredSize := meta.size
- if !packfmt.IsBaseObjectType(meta.ty) {
- declaredSize, err = deltaDeclaredSizeAt(pack, meta.dataOffset)
- if err != nil {
- return objecttype.TypeInvalid, nil, err
- }
- }
-
- return store.deltaResolveChain(chain, declaredSize)
-}
-
-// deltaResolveChain resolves one object chain into content bytes.
-func (store *Store) deltaResolveChain(chain deltaChain, declaredSize int64) (objecttype.Type, []byte, error) {
- ty, out, nextDelta, err := store.deltaResolveChainStart(chain)
- if err != nil {
- return objecttype.TypeInvalid, nil, err
- }
-
- for i := nextDelta; i >= 0; i-- {
- node := chain.deltas[i]
-
- pack, err := store.openPack(node.loc.packName)
- if err != nil {
- return objecttype.TypeInvalid, nil, err
- }
-
- delta, err := inflateAt(pack, node.dataOffset, -1)
- if err != nil {
- return objecttype.TypeInvalid, nil, err
- }
-
- out, err = deltaapply.Apply(out, delta)
- if err != nil {
- return objecttype.TypeInvalid, nil, err
- }
-
- store.cacheMu.Lock()
- store.deltaCache.add(
- deltaBaseKey{packName: node.loc.packName, offset: node.loc.offset},
- ty,
- out,
- )
- store.cacheMu.Unlock()
- }
-
- if int64(len(out)) != declaredSize {
- return objecttype.TypeInvalid, nil, fmt.Errorf(
- "objectstore/packed: resolved content size mismatch: got %d want %d",
- len(out),
- declaredSize,
- )
- }
-
- if ty != chain.baseType {
- return objecttype.TypeInvalid, nil, fmt.Errorf(
- "objectstore/packed: resolved content type mismatch: got %d want %d",
- ty,
- chain.baseType,
- )
- }
-
- return ty, out, nil
-}
-
-// deltaResolveChainStart finds the nearest cached chain node or inflates the
-// innermost base object. It returns the starting bytes and the next delta index
-// to apply in reverse order.
-func (store *Store) deltaResolveChainStart(chain deltaChain) (objecttype.Type, []byte, int, error) {
- for i, node := range chain.deltas {
- store.cacheMu.RLock()
- ty, out, ok := store.deltaCache.get(
- deltaBaseKey{packName: node.loc.packName, offset: node.loc.offset},
- )
- store.cacheMu.RUnlock()
-
- if ok {
- return ty, out, i - 1, nil
- }
- }
-
- store.cacheMu.RLock()
- ty, out, ok := store.deltaCache.get(
- deltaBaseKey{packName: chain.baseLoc.packName, offset: chain.baseLoc.offset},
- )
- store.cacheMu.RUnlock()
-
- if ok {
- return ty, out, len(chain.deltas) - 1, nil
- }
-
- pack, meta, err := store.entryMetaAt(chain.baseLoc)
- if err != nil {
- return objecttype.TypeInvalid, nil, 0, err
- }
-
- if !packfmt.IsBaseObjectType(meta.ty) {
- return objecttype.TypeInvalid, nil, 0, fmt.Errorf("objectstore/packed: delta chain base is not a base object")
- }
-
- base, err := inflateAt(pack, meta.dataOffset, meta.size)
- if err != nil {
- return objecttype.TypeInvalid, nil, 0, err
- }
-
- store.cacheMu.Lock()
- store.deltaCache.add(
- deltaBaseKey{packName: chain.baseLoc.packName, offset: chain.baseLoc.offset},
- meta.ty,
- base,
- )
- store.cacheMu.Unlock()
-
- return meta.ty, base, len(chain.deltas) - 1, nil
-}
diff --git a/objectstore/packed/delta_plan.go b/objectstore/packed/delta_build_chain.go
index b0b0324c..7a5f3c16 100644
--- a/objectstore/packed/delta_plan.go
+++ b/objectstore/packed/delta_build_chain.go
@@ -1,32 +1,12 @@
package packed
import (
- "bufio"
"fmt"
- deltaapply "codeberg.org/lindenii/furgit/format/delta/apply"
packfmt "codeberg.org/lindenii/furgit/format/pack"
"codeberg.org/lindenii/furgit/objecttype"
)
-// deltaNode describes one delta object in a reconstruction chain.
-type deltaNode struct {
- // loc identifies the delta object's pack location.
- loc location
- // dataOffset points to the start of the delta zlib payload in pack.
- dataOffset int
-}
-
-// deltaChain describes how to reconstruct one requested object.
-type deltaChain struct {
- // baseLoc points to the innermost base object.
- baseLoc location
- // baseType is the canonical object type resolved from baseLoc.
- baseType objecttype.Type
- // deltas contains delta objects from target down toward base.
- deltas []deltaNode
-}
-
// deltaBuildChain walks one object's chain and builds a reconstruction chain.
func (store *Store) deltaBuildChain(start location) (deltaChain, error) {
visited := make(map[location]struct{})
@@ -84,23 +64,3 @@ func (store *Store) deltaBuildChain(start location) (deltaChain, error) {
}
}
}
-
-// deltaDeclaredSizeAt returns the resolved object size declared by one delta
-// stream header at dataOffset.
-func deltaDeclaredSizeAt(pack *packFile, dataOffset int) (int64, error) {
- reader, err := zlibReaderAt(pack, dataOffset)
- if err != nil {
- return 0, err
- }
-
- defer func() { _ = reader.Close() }()
-
- br := bufio.NewReaderSize(reader, 32)
-
- _, size, err := deltaapply.ReadHeaderSizes(br)
- if err != nil {
- return 0, err
- }
-
- return int64(size), nil
-}
diff --git a/objectstore/packed/delta_cache.go b/objectstore/packed/delta_cache.go
index a911b254..08040620 100644
--- a/objectstore/packed/delta_cache.go
+++ b/objectstore/packed/delta_cache.go
@@ -5,6 +5,8 @@ import (
"codeberg.org/lindenii/furgit/objecttype"
)
+const defaultDeltaCacheMaxBytes = 32 << 20
+
// deltaBaseKey identifies one base object by pack location.
type deltaBaseKey struct {
packName string
diff --git a/objectstore/packed/delta_chain.go b/objectstore/packed/delta_chain.go
new file mode 100644
index 00000000..d473a25c
--- /dev/null
+++ b/objectstore/packed/delta_chain.go
@@ -0,0 +1,13 @@
+package packed
+
+import "codeberg.org/lindenii/furgit/objecttype"
+
+// deltaChain describes how to reconstruct one requested object.
+type deltaChain struct {
+ // baseLoc points to the innermost base object.
+ baseLoc location
+ // baseType is the canonical object type resolved from baseLoc.
+ baseType objecttype.Type
+ // deltas contains delta objects from target down toward base.
+ deltas []deltaNode
+}
diff --git a/objectstore/packed/delta_node.go b/objectstore/packed/delta_node.go
new file mode 100644
index 00000000..24ede1e0
--- /dev/null
+++ b/objectstore/packed/delta_node.go
@@ -0,0 +1,9 @@
+package packed
+
+// deltaNode describes one delta object in a reconstruction chain.
+type deltaNode struct {
+ // loc identifies the delta object's pack location.
+ loc location
+ // dataOffset points to the start of the delta zlib payload in pack.
+ dataOffset int
+}
diff --git a/objectstore/packed/delta_resolve_chain.go b/objectstore/packed/delta_resolve_chain.go
new file mode 100644
index 00000000..e12bda88
--- /dev/null
+++ b/objectstore/packed/delta_resolve_chain.go
@@ -0,0 +1,61 @@
+package packed
+
+import (
+ "fmt"
+
+ deltaapply "codeberg.org/lindenii/furgit/format/delta/apply"
+ "codeberg.org/lindenii/furgit/objecttype"
+)
+
+// deltaResolveChain resolves one object chain into content bytes.
+func (store *Store) deltaResolveChain(chain deltaChain, declaredSize int64) (objecttype.Type, []byte, error) {
+ ty, out, nextDelta, err := store.deltaResolveChainStart(chain)
+ if err != nil {
+ return objecttype.TypeInvalid, nil, err
+ }
+
+ for i := nextDelta; i >= 0; i-- {
+ node := chain.deltas[i]
+
+ pack, err := store.openPack(node.loc.packName)
+ if err != nil {
+ return objecttype.TypeInvalid, nil, err
+ }
+
+ delta, err := inflateAt(pack, node.dataOffset, -1)
+ if err != nil {
+ return objecttype.TypeInvalid, nil, err
+ }
+
+ out, err = deltaapply.Apply(out, delta)
+ if err != nil {
+ return objecttype.TypeInvalid, nil, err
+ }
+
+ store.cacheMu.Lock()
+ store.deltaCache.add(
+ deltaBaseKey{packName: node.loc.packName, offset: node.loc.offset},
+ ty,
+ out,
+ )
+ store.cacheMu.Unlock()
+ }
+
+ if int64(len(out)) != declaredSize {
+ return objecttype.TypeInvalid, nil, fmt.Errorf(
+ "objectstore/packed: resolved content size mismatch: got %d want %d",
+ len(out),
+ declaredSize,
+ )
+ }
+
+ if ty != chain.baseType {
+ return objecttype.TypeInvalid, nil, fmt.Errorf(
+ "objectstore/packed: resolved content type mismatch: got %d want %d",
+ ty,
+ chain.baseType,
+ )
+ }
+
+ return ty, out, nil
+}
diff --git a/objectstore/packed/delta_resolve_chain_start.go b/objectstore/packed/delta_resolve_chain_start.go
new file mode 100644
index 00000000..70266565
--- /dev/null
+++ b/objectstore/packed/delta_resolve_chain_start.go
@@ -0,0 +1,59 @@
+package packed
+
+import (
+ "fmt"
+
+ packfmt "codeberg.org/lindenii/furgit/format/pack"
+ "codeberg.org/lindenii/furgit/objecttype"
+)
+
+// deltaResolveChainStart finds the nearest cached chain node or inflates the
+// innermost base object. It returns the starting bytes and the next delta index
+// to apply in reverse order.
+func (store *Store) deltaResolveChainStart(chain deltaChain) (objecttype.Type, []byte, int, error) {
+ for i, node := range chain.deltas {
+ store.cacheMu.RLock()
+ ty, out, ok := store.deltaCache.get(
+ deltaBaseKey{packName: node.loc.packName, offset: node.loc.offset},
+ )
+ store.cacheMu.RUnlock()
+
+ if ok {
+ return ty, out, i - 1, nil
+ }
+ }
+
+ store.cacheMu.RLock()
+ ty, out, ok := store.deltaCache.get(
+ deltaBaseKey{packName: chain.baseLoc.packName, offset: chain.baseLoc.offset},
+ )
+ store.cacheMu.RUnlock()
+
+ if ok {
+ return ty, out, len(chain.deltas) - 1, nil
+ }
+
+ pack, meta, err := store.entryMetaAt(chain.baseLoc)
+ if err != nil {
+ return objecttype.TypeInvalid, nil, 0, err
+ }
+
+ if !packfmt.IsBaseObjectType(meta.ty) {
+ return objecttype.TypeInvalid, nil, 0, fmt.Errorf("objectstore/packed: delta chain base is not a base object")
+ }
+
+ base, err := inflateAt(pack, meta.dataOffset, meta.size)
+ if err != nil {
+ return objecttype.TypeInvalid, nil, 0, err
+ }
+
+ store.cacheMu.Lock()
+ store.deltaCache.add(
+ deltaBaseKey{packName: chain.baseLoc.packName, offset: chain.baseLoc.offset},
+ meta.ty,
+ base,
+ )
+ store.cacheMu.Unlock()
+
+ return meta.ty, base, len(chain.deltas) - 1, nil
+}
diff --git a/objectstore/packed/delta_resolve_content.go b/objectstore/packed/delta_resolve_content.go
new file mode 100644
index 00000000..a8de9cbc
--- /dev/null
+++ b/objectstore/packed/delta_resolve_content.go
@@ -0,0 +1,29 @@
+package packed
+
+import (
+ packfmt "codeberg.org/lindenii/furgit/format/pack"
+ "codeberg.org/lindenii/furgit/objecttype"
+)
+
+// deltaResolveContent resolves one object's content bytes from its pack location.
+func (store *Store) deltaResolveContent(start location) (objecttype.Type, []byte, error) {
+ chain, err := store.deltaBuildChain(start)
+ if err != nil {
+ return objecttype.TypeInvalid, nil, err
+ }
+
+ pack, meta, err := store.entryMetaAt(start)
+ if err != nil {
+ return objecttype.TypeInvalid, nil, err
+ }
+
+ declaredSize := meta.size
+ if !packfmt.IsBaseObjectType(meta.ty) {
+ declaredSize, err = deltaDeclaredSizeAt(pack, meta.dataOffset)
+ if err != nil {
+ return objecttype.TypeInvalid, nil, err
+ }
+ }
+
+ return store.deltaResolveChain(chain, declaredSize)
+}
diff --git a/objectstore/packed/delta_size.go b/objectstore/packed/delta_size.go
new file mode 100644
index 00000000..ca0ccb25
--- /dev/null
+++ b/objectstore/packed/delta_size.go
@@ -0,0 +1,27 @@
+package packed
+
+import (
+ "bufio"
+
+ deltaapply "codeberg.org/lindenii/furgit/format/delta/apply"
+)
+
+// deltaDeclaredSizeAt returns the resolved object size declared by one delta
+// stream header at dataOffset.
+func deltaDeclaredSizeAt(pack *packFile, dataOffset int) (int64, error) {
+ reader, err := zlibReaderAt(pack, dataOffset)
+ if err != nil {
+ return 0, err
+ }
+
+ defer func() { _ = reader.Close() }()
+
+ br := bufio.NewReaderSize(reader, 32)
+
+ _, size, err := deltaapply.ReadHeaderSizes(br)
+ if err != nil {
+ return 0, err
+ }
+
+ return int64(size), nil
+}
diff --git a/objectstore/packed/entry_meta.go b/objectstore/packed/entry_meta.go
new file mode 100644
index 00000000..0bbe8bef
--- /dev/null
+++ b/objectstore/packed/entry_meta.go
@@ -0,0 +1,16 @@
+package packed
+
+// entryMetaAt parses one pack entry header at location.
+func (store *Store) entryMetaAt(loc location) (*packFile, entryMeta, error) {
+ pack, err := store.openPack(loc.packName)
+ if err != nil {
+ return nil, entryMeta{}, err
+ }
+
+ meta, err := parseEntryMeta(pack, store.algo, loc.offset)
+ if err != nil {
+ return nil, entryMeta{}, err
+ }
+
+ return pack, meta, nil
+}
diff --git a/objectstore/packed/idx.go b/objectstore/packed/idx.go
new file mode 100644
index 00000000..db6a0136
--- /dev/null
+++ b/objectstore/packed/idx.go
@@ -0,0 +1,36 @@
+package packed
+
+import (
+ "os"
+
+ "codeberg.org/lindenii/furgit/objectid"
+)
+
+// idxFile stores one mapped and validated idx v2 file.
+type idxFile struct {
+ // idxName is the basename of this .idx file.
+ idxName string
+ // packName is the matching .pack basename.
+ packName string
+ // algo is the hash algorithm encoded by the index.
+ algo objectid.Algorithm
+
+ // file is the opened index file descriptor.
+ file *os.File
+ // data is the mapped index bytes.
+ data []byte
+
+ // fanout stores fanout table values.
+ fanout [256]uint32
+ // numObjects equals fanout[255].
+ numObjects int
+
+ // namesOffset starts the sorted object-id table.
+ namesOffset int
+ // offset32Offset starts the 32-bit offset table.
+ offset32Offset int
+ // offset64Offset starts the 64-bit offset table.
+ offset64Offset int
+ // offset64Count is the number of 64-bit offset entries.
+ offset64Count int
+}
diff --git a/objectstore/packed/idx_candidate.go b/objectstore/packed/idx_candidate.go
new file mode 100644
index 00000000..2f2ad7a9
--- /dev/null
+++ b/objectstore/packed/idx_candidate.go
@@ -0,0 +1,10 @@
+package packed
+
+// candidateForPack returns one discovered candidate for a pack basename.
+func (store *Store) candidateForPack(packName string) (packCandidate, bool) {
+ store.candidatesMu.RLock()
+ candidate, ok := store.candidateByPack[packName]
+ store.candidatesMu.RUnlock()
+
+ return candidate, ok
+}
diff --git a/objectstore/packed/idx_close.go b/objectstore/packed/idx_close.go
new file mode 100644
index 00000000..814ec987
--- /dev/null
+++ b/objectstore/packed/idx_close.go
@@ -0,0 +1,28 @@
+package packed
+
+import "syscall"
+
+// close unmaps and closes one idx handle.
+func (index *idxFile) close() error {
+ var closeErr error
+
+ if index.data != nil {
+ err := syscall.Munmap(index.data)
+ if err != nil && closeErr == nil {
+ closeErr = err
+ }
+
+ index.data = nil
+ }
+
+ if index.file != nil {
+ err := index.file.Close()
+ if err != nil && closeErr == nil {
+ closeErr = err
+ }
+
+ index.file = nil
+ }
+
+ return closeErr
+}
diff --git a/objectstore/packed/idx_lookup_candidates.go b/objectstore/packed/idx_lookup_candidates.go
index 508da2ef..9534476a 100644
--- a/objectstore/packed/idx_lookup_candidates.go
+++ b/objectstore/packed/idx_lookup_candidates.go
@@ -7,12 +7,6 @@ import (
"strings"
)
-// location identifies one object entry in a specific pack file.
-type location struct {
- packName string
- offset uint64
-}
-
// packCandidate describes one discovered pack/index pair.
type packCandidate struct {
// packName is the .pack basename.
diff --git a/objectstore/packed/idx_open.go b/objectstore/packed/idx_open.go
index c3c97e4d..9eb92682 100644
--- a/objectstore/packed/idx_open.go
+++ b/objectstore/packed/idx_open.go
@@ -9,44 +9,6 @@ import (
"codeberg.org/lindenii/furgit/objectid"
)
-// idxFile stores one mapped and validated idx v2 file.
-type idxFile struct {
- // idxName is the basename of this .idx file.
- idxName string
- // packName is the matching .pack basename.
- packName string
- // algo is the hash algorithm encoded by the index.
- algo objectid.Algorithm
-
- // file is the opened index file descriptor.
- file *os.File
- // data is the mapped index bytes.
- data []byte
-
- // fanout stores fanout table values.
- fanout [256]uint32
- // numObjects equals fanout[255].
- numObjects int
-
- // namesOffset starts the sorted object-id table.
- namesOffset int
- // offset32Offset starts the 32-bit offset table.
- offset32Offset int
- // offset64Offset starts the 64-bit offset table.
- offset64Offset int
- // offset64Count is the number of 64-bit offset entries.
- offset64Count int
-}
-
-// candidateForPack returns one discovered candidate for a pack basename.
-func (store *Store) candidateForPack(packName string) (packCandidate, bool) {
- store.candidatesMu.RLock()
- candidate, ok := store.candidateByPack[packName]
- store.candidatesMu.RUnlock()
-
- return candidate, ok
-}
-
// openIndex returns one opened and parsed index, caching it by pack basename.
func (store *Store) openIndex(candidate packCandidate) (*idxFile, error) {
store.idxMu.RLock()
@@ -134,28 +96,3 @@ func openIdxFile(root *os.Root, idxName, packName string, algo objectid.Algorith
return index, nil
}
-
-// close unmaps and closes one idx handle.
-func (index *idxFile) close() error {
- var closeErr error
-
- if index.data != nil {
- err := syscall.Munmap(index.data)
- if err != nil && closeErr == nil {
- closeErr = err
- }
-
- index.data = nil
- }
-
- if index.file != nil {
- err := index.file.Close()
- if err != nil && closeErr == nil {
- closeErr = err
- }
-
- index.file = nil
- }
-
- return closeErr
-}
diff --git a/objectstore/packed/location.go b/objectstore/packed/location.go
new file mode 100644
index 00000000..82d17c17
--- /dev/null
+++ b/objectstore/packed/location.go
@@ -0,0 +1,7 @@
+package packed
+
+// location identifies one object entry in a specific pack file.
+type location struct {
+ packName string
+ offset uint64
+}
diff --git a/objectstore/packed/new.go b/objectstore/packed/new.go
new file mode 100644
index 00000000..407bc1d0
--- /dev/null
+++ b/objectstore/packed/new.go
@@ -0,0 +1,24 @@
+package packed
+
+import (
+ "os"
+
+ "codeberg.org/lindenii/furgit/objectid"
+)
+
+// New creates a packed-object store rooted at an objects/pack directory.
+func New(root *os.Root, algo objectid.Algorithm) (*Store, error) {
+ if algo.Size() == 0 {
+ return nil, objectid.ErrInvalidAlgorithm
+ }
+
+ return &Store{
+ root: root,
+ algo: algo,
+ candidateByPack: make(map[string]packCandidate),
+ candidateNodeByPack: make(map[string]*packCandidateNode),
+ idxByPack: make(map[string]*idxFile),
+ packs: make(map[string]*packFile),
+ deltaCache: newDeltaCache(defaultDeltaCacheMaxBytes),
+ }, nil
+}
diff --git a/objectstore/packed/read_closer.go b/objectstore/packed/read_closer.go
new file mode 100644
index 00000000..c317d002
--- /dev/null
+++ b/objectstore/packed/read_closer.go
@@ -0,0 +1,19 @@
+package packed
+
+import "io"
+
+// readCloser proxies reads and closes one underlying closer.
+type readCloser struct {
+ reader io.Reader
+ closer io.Closer
+}
+
+// Read proxies reads to the underlying reader.
+func (reader *readCloser) Read(dst []byte) (int, error) {
+ return reader.reader.Read(dst)
+}
+
+// Close closes the underlying closer.
+func (reader *readCloser) Close() error {
+ return reader.closer.Close()
+}
diff --git a/objectstore/packed/read_reader.go b/objectstore/packed/read_reader.go
index d8dfdca9..d5a94482 100644
--- a/objectstore/packed/read_reader.go
+++ b/objectstore/packed/read_reader.go
@@ -12,22 +12,6 @@ import (
"codeberg.org/lindenii/furgit/objecttype"
)
-// readCloser proxies reads and closes one underlying closer.
-type readCloser struct {
- reader io.Reader
- closer io.Closer
-}
-
-// Read proxies reads to the underlying reader.
-func (reader *readCloser) Read(dst []byte) (int, error) {
- return reader.reader.Read(dst)
-}
-
-// Close closes the underlying closer.
-func (reader *readCloser) Close() error {
- return reader.closer.Close()
-}
-
// ReadReaderContent reads an object's type, declared content size, and content stream.
//
// The caller must close the returned reader.
diff --git a/objectstore/packed/store.go b/objectstore/packed/store.go
index 2da48dff..000e04f2 100644
--- a/objectstore/packed/store.go
+++ b/objectstore/packed/store.go
@@ -49,69 +49,4 @@ type Store struct {
closed bool
}
-const defaultDeltaCacheMaxBytes = 32 << 20
-
var _ objectstore.Store = (*Store)(nil)
-
-// New creates a packed-object store rooted at an objects/pack directory.
-func New(root *os.Root, algo objectid.Algorithm) (*Store, error) {
- if algo.Size() == 0 {
- return nil, objectid.ErrInvalidAlgorithm
- }
-
- return &Store{
- root: root,
- algo: algo,
- candidateByPack: make(map[string]packCandidate),
- candidateNodeByPack: make(map[string]*packCandidateNode),
- idxByPack: make(map[string]*idxFile),
- packs: make(map[string]*packFile),
- deltaCache: newDeltaCache(defaultDeltaCacheMaxBytes),
- }, nil
-}
-
-// Close releases mapped pack/index resources associated with the store.
-func (store *Store) Close() error {
- store.stateMu.Lock()
-
- if store.closed {
- store.stateMu.Unlock()
-
- return nil
- }
-
- store.closed = true
- root := store.root
- packs := store.packs
- store.stateMu.Unlock()
- store.idxMu.RLock()
- indexes := store.idxByPack
- store.idxMu.RUnlock()
-
- var closeErr error
-
- for _, pack := range packs {
- err := pack.close()
- if err != nil && closeErr == nil {
- closeErr = err
- }
- }
-
- for _, index := range indexes {
- err := index.close()
- if err != nil && closeErr == nil {
- closeErr = err
- }
- }
-
- store.cacheMu.Lock()
- store.deltaCache.clear()
- store.cacheMu.Unlock()
-
- err := root.Close()
- if err != nil && closeErr == nil {
- closeErr = err
- }
-
- return closeErr
-}
diff --git a/objectstore/packed/store_open_pack.go b/objectstore/packed/store_open_pack.go
index f101b624..c621e08c 100644
--- a/objectstore/packed/store_open_pack.go
+++ b/objectstore/packed/store_open_pack.go
@@ -1,7 +1,5 @@
package packed
-import "fmt"
-
// openPack returns one opened and validated pack handle.
func (store *Store) openPack(name string) (*packFile, error) {
store.stateMu.RLock()
@@ -57,44 +55,3 @@ func (store *Store) openPack(name string) (*packFile, error) {
return pack, nil
}
-
-// verifyPackMatchesIndexes checks that one opened pack's trailer hash matches
-// every loaded index that references the same pack name.
-func (store *Store) verifyPackMatchesIndexes(pack *packFile) error {
- err := store.ensureCandidates()
- if err != nil {
- return err
- }
-
- candidate, ok := store.candidateForPack(pack.name)
- if !ok {
- return fmt.Errorf("objectstore/packed: missing index for pack %q", pack.name)
- }
-
- index, err := store.openIndex(candidate)
- if err != nil {
- return err
- }
-
- err = verifyMappedPackMatchesMappedIdx(pack.data, index.data, store.algo)
- if err != nil {
- return fmt.Errorf("objectstore/packed: pack %q does not match idx %q: %w", pack.name, index.idxName, err)
- }
-
- return nil
-}
-
-// entryMetaAt parses one pack entry header at location.
-func (store *Store) entryMetaAt(loc location) (*packFile, entryMeta, error) {
- pack, err := store.openPack(loc.packName)
- if err != nil {
- return nil, entryMeta{}, err
- }
-
- meta, err := parseEntryMeta(pack, store.algo, loc.offset)
- if err != nil {
- return nil, entryMeta{}, err
- }
-
- return pack, meta, nil
-}
diff --git a/objectstore/packed/trailer_match.go b/objectstore/packed/trailer_match.go
new file mode 100644
index 00000000..25337cd7
--- /dev/null
+++ b/objectstore/packed/trailer_match.go
@@ -0,0 +1,29 @@
+package packed
+
+import "fmt"
+
+// verifyPackMatchesIndexes checks that one opened pack's trailer hash matches
+// every loaded index that references the same pack name.
+func (store *Store) verifyPackMatchesIndexes(pack *packFile) error {
+ err := store.ensureCandidates()
+ if err != nil {
+ return err
+ }
+
+ candidate, ok := store.candidateForPack(pack.name)
+ if !ok {
+ return fmt.Errorf("objectstore/packed: missing index for pack %q", pack.name)
+ }
+
+ index, err := store.openIndex(candidate)
+ if err != nil {
+ return err
+ }
+
+ err = verifyMappedPackMatchesMappedIdx(pack.data, index.data, store.algo)
+ if err != nil {
+ return fmt.Errorf("objectstore/packed: pack %q does not match idx %q: %w", pack.name, index.idxName, err)
+ }
+
+ return nil
+}