aboutsummaryrefslogtreecommitdiff
path: root/objectstore/loose/write_bytes.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-02-21 04:55:02 +0800
committerGravatar Runxi Yu2026-02-21 04:55:02 +0800
commit564c8ecc84ed1bfc28ea3a0251020051906b8548 (patch)
tree1961ff46e328a997ffc2d2f19f53ee16f0952d3a /objectstore/loose/write_bytes.go
parentobjectstore/loose: Add loose writer in bytes (diff)
signatureNo signature
objectstore/loose: Add streaming writer
Diffstat (limited to 'objectstore/loose/write_bytes.go')
-rw-r--r--objectstore/loose/write_bytes.go109
1 files changed, 15 insertions, 94 deletions
diff --git a/objectstore/loose/write_bytes.go b/objectstore/loose/write_bytes.go
index fe2bafb9..1f7ab59f 100644
--- a/objectstore/loose/write_bytes.go
+++ b/objectstore/loose/write_bytes.go
@@ -1,123 +1,44 @@
package loose
import (
- "compress/zlib"
- "crypto/rand"
- "errors"
- "fmt"
- "io/fs"
- "os"
- "path/filepath"
+ "bytes"
- "codeberg.org/lindenii/furgit/objectheader"
"codeberg.org/lindenii/furgit/objectid"
"codeberg.org/lindenii/furgit/objecttype"
)
-const tempObjectFilePrefix = "tmp_obj_"
-
// WriteBytesFull writes a full serialized object as "type size\\x00content".
func (store *Store) WriteBytesFull(raw []byte) (objectid.ObjectID, error) {
var zero objectid.ObjectID
- if _, _, err := parseRaw(raw); err != nil {
+ writer, finalize, err := store.WriteWriterFull()
+ if err != nil {
return zero, err
}
-
- id := store.algo.Sum(raw)
- relPath, err := store.objectPath(id)
- if err != nil {
+ if _, err := bytes.NewReader(raw).WriteTo(writer); err != nil {
+ _ = writer.Close()
return zero, err
}
- if err := store.writeCompressedAtomic(relPath, raw); err != nil {
+ if err := writer.Close(); err != nil {
return zero, err
}
- return id, nil
+ return finalize()
}
// WriteBytesContent writes typed content bytes as a loose object.
func (store *Store) WriteBytesContent(ty objecttype.Type, content []byte) (objectid.ObjectID, error) {
var zero objectid.ObjectID
- header, ok := objectheader.Encode(ty, int64(len(content)))
- if !ok {
- return zero, fmt.Errorf("objectstore/loose: failed to encode object header for type %d", ty)
- }
-
- raw := make([]byte, len(header)+len(content))
- copy(raw, header)
- copy(raw[len(header):], content)
- return store.WriteBytesFull(raw)
-}
-
-// writeCompressedAtomic compresses raw and writes it to relPath atomically.
-func (store *Store) writeCompressedAtomic(relPath string, raw []byte) error {
- if _, err := store.root.Stat(relPath); err == nil {
- return nil
- } else if !errors.Is(err, fs.ErrNotExist) {
- return err
- }
-
- dir := filepath.Dir(relPath)
- if err := store.root.MkdirAll(dir, 0o755); err != nil {
- return err
- }
-
- tmpRelPath, tmpFile, err := store.createTempObjectFile(dir)
+ writer, finalize, err := store.WriteWriterContent(ty, int64(len(content)))
if err != nil {
- return err
- }
-
- cleanup := true
- defer func() {
- if tmpFile != nil {
- _ = tmpFile.Close()
- }
- if cleanup {
- _ = store.root.Remove(tmpRelPath)
- }
- }()
-
- zw := zlib.NewWriter(tmpFile)
- if _, err := zw.Write(raw); err != nil {
- _ = zw.Close()
- return err
- }
- if err := zw.Close(); err != nil {
- return err
- }
- if err := tmpFile.Sync(); err != nil {
- return err
- }
- if err := tmpFile.Close(); err != nil {
- return err
+ return zero, err
}
- tmpFile = nil
-
- if err := store.root.Rename(tmpRelPath, relPath); err != nil {
- if errors.Is(err, fs.ErrExist) {
- return nil
- }
- return err
+ if _, err := bytes.NewReader(content).WriteTo(writer); err != nil {
+ _ = writer.Close()
+ return zero, err
}
-
- cleanup = false
- return nil
-}
-
-// createTempObjectFile creates a unique temporary object file within dir.
-func (store *Store) createTempObjectFile(dir string) (string, *os.File, error) {
- for range 16 {
- relPath := filepath.Join(dir, tempObjectFilePrefix+rand.Text())
- file, err := store.root.OpenFile(relPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o644)
- if err == nil {
- return relPath, file, nil
- }
- if errors.Is(err, fs.ErrExist) {
- continue
- }
- return "", nil, err
+ if err := writer.Close(); err != nil {
+ return zero, err
}
-
- return "", nil, errors.New("objectstore/loose: failed to create temporary object file")
+ return finalize()
}