summaryrefslogtreecommitdiffhomepage
path: root/internal/history
diff options
context:
space:
mode:
authorKujtim Hoxha <[email protected]>2025-04-17 13:45:26 +0200
committerKujtim Hoxha <[email protected]>2025-04-21 13:42:02 +0200
commitc24e3c18e0177e2e059f622a63e87249c52db2d5 (patch)
tree51900cfe51292d61aa137ea03d43039aff627a71 /internal/history
parentcaea29375994373f6027c8dc4d8aa536c4e135e7 (diff)
downloadopencode-c24e3c18e0177e2e059f622a63e87249c52db2d5.tar.gz
opencode-c24e3c18e0177e2e059f622a63e87249c52db2d5.zip
small improvements
Diffstat (limited to 'internal/history')
-rw-r--r--internal/history/file.go76
1 files changed, 62 insertions, 14 deletions
diff --git a/internal/history/file.go b/internal/history/file.go
index 1e8bc50bb..8453ac272 100644
--- a/internal/history/file.go
+++ b/internal/history/file.go
@@ -2,9 +2,11 @@ package history
import (
"context"
+ "database/sql"
"fmt"
"strconv"
"strings"
+ "time"
"github.com/google/uuid"
"github.com/kujtimiihoxha/opencode/internal/db"
@@ -40,10 +42,11 @@ type Service interface {
type service struct {
*pubsub.Broker[File]
- q db.Querier
+ db *sql.DB
+ q *db.Queries
}
-func NewService(q db.Querier) Service {
+func NewService(q *db.Queries, db *sql.DB) Service {
return &service{
Broker: pubsub.NewBroker[File](),
q: q,
@@ -91,19 +94,64 @@ func (s *service) CreateVersion(ctx context.Context, sessionID, path, content st
}
func (s *service) createWithVersion(ctx context.Context, sessionID, path, content, version string) (File, error) {
- dbFile, err := s.q.CreateFile(ctx, db.CreateFileParams{
- ID: uuid.New().String(),
- SessionID: sessionID,
- Path: path,
- Content: content,
- Version: version,
- })
- if err != nil {
- return File{}, err
+ // Maximum number of retries for transaction conflicts
+ const maxRetries = 3
+ var file File
+ var err error
+
+ // Retry loop for transaction conflicts
+ for attempt := 0; attempt < maxRetries; attempt++ {
+ // Start a transaction
+ tx, err := s.db.BeginTx(ctx, nil)
+ if err != nil {
+ return File{}, fmt.Errorf("failed to begin transaction: %w", err)
+ }
+
+ // Create a new queries instance with the transaction
+ qtx := s.q.WithTx(tx)
+
+ // Try to create the file within the transaction
+ dbFile, err := qtx.CreateFile(ctx, db.CreateFileParams{
+ ID: uuid.New().String(),
+ SessionID: sessionID,
+ Path: path,
+ Content: content,
+ Version: version,
+ })
+ if err != nil {
+ // Rollback the transaction
+ tx.Rollback()
+
+ // Check if this is a uniqueness constraint violation
+ if strings.Contains(err.Error(), "UNIQUE constraint failed") {
+ if attempt < maxRetries-1 {
+ // If we have retries left, generate a new version and try again
+ if strings.HasPrefix(version, "v") {
+ versionNum, parseErr := strconv.Atoi(version[1:])
+ if parseErr == nil {
+ version = fmt.Sprintf("v%d", versionNum+1)
+ continue
+ }
+ }
+ // If we can't parse the version, use a timestamp-based version
+ version = fmt.Sprintf("v%d", time.Now().Unix())
+ continue
+ }
+ }
+ return File{}, err
+ }
+
+ // Commit the transaction
+ if err = tx.Commit(); err != nil {
+ return File{}, fmt.Errorf("failed to commit transaction: %w", err)
+ }
+
+ file = s.fromDBItem(dbFile)
+ s.Publish(pubsub.CreatedEvent, file)
+ return file, nil
}
- file := s.fromDBItem(dbFile)
- s.Publish(pubsub.CreatedEvent, file)
- return file, nil
+
+ return file, err
}
func (s *service) Get(ctx context.Context, id string) (File, error) {