Severity: major Commit:488f11b — alpha Затронутые места:
service/version.go строки 135–156
В чём проблема
Отсутствие атомарности при создании snapshot-версии. Операции CreateVersion и UpdateLatestVersion выполняются без транзакции. Если вторая операция завершится ошибкой, в базе останется 'сиротская' версия, а документ будет ссылаться на старую версию, что нарушает консистентность данных.
Цитата кода
if s.snapshotInterval > 0 && !isSnapshot {
// считаем количество версий от этого snapshot'а до новой версии
// простая реализация: пройти вверх по родителям и посчитать
count := 0
curr := &newVer
for {
count++
if curr.ParentID == nil {
break
}
parent, err := s.storage.GetParentVersion(curr)
if err != nil {
break
}
if parent == nil {
break
}
curr = parent
if curr.IsSnapshot {
break
}
}
if count >= s.snapshotInterval {
// делаем snapshot: восстанавливаем полную версию и сохраняем snapshot-версию
full, err := s.ReconstructVersion(newVer.ID)
if err == nil {
snapVer := models.Version{
ID: uuid.New(),
DocumentID: docID,
ParentID: &newVer.ID,
IsSnapshot: true,
Snapshot: full,
CreatedAt: time.Now(),
}
// сохраняем snapshot-версию и обновляем latest_version
_ = s.storage.CreateVersion(&snapVer)
_ = s.storage.UpdateLatestVersion(docID, snapVer.ID)
}
}
}
Как исправить
Вариант 1 — Обернуть операции в транзакцию на уровне хранилища или сервиса.
Необходимо добавить метод в IVersionStorage для выполнения операций в рамках одной транзакции, либо передавать объект транзакции в методы.
Автоматическая проверка commit-keeper · модель gemma4:31b · sha=488f11b
**Severity:** major
**Commit:** [`488f11b`](https://git.gm6.ru/icewind/seadoc/commit/488f11bd56db4f7e17b4b4bd9bd6e6f4f4a394c5) — alpha
**Затронутые места:**
- `service/version.go` строки 135–156
## В чём проблема
Отсутствие атомарности при создании snapshot-версии. Операции CreateVersion и UpdateLatestVersion выполняются без транзакции. Если вторая операция завершится ошибкой, в базе останется 'сиротская' версия, а документ будет ссылаться на старую версию, что нарушает консистентность данных.
## Цитата кода
```
if s.snapshotInterval > 0 && !isSnapshot {
// считаем количество версий от этого snapshot'а до новой версии
// простая реализация: пройти вверх по родителям и посчитать
count := 0
curr := &newVer
for {
count++
if curr.ParentID == nil {
break
}
parent, err := s.storage.GetParentVersion(curr)
if err != nil {
break
}
if parent == nil {
break
}
curr = parent
if curr.IsSnapshot {
break
}
}
if count >= s.snapshotInterval {
// делаем snapshot: восстанавливаем полную версию и сохраняем snapshot-версию
full, err := s.ReconstructVersion(newVer.ID)
if err == nil {
snapVer := models.Version{
ID: uuid.New(),
DocumentID: docID,
ParentID: &newVer.ID,
IsSnapshot: true,
Snapshot: full,
CreatedAt: time.Now(),
}
// сохраняем snapshot-версию и обновляем latest_version
_ = s.storage.CreateVersion(&snapVer)
_ = s.storage.UpdateLatestVersion(docID, snapVer.ID)
}
}
}
```
## Как исправить
### Вариант 1 — Обернуть операции в транзакцию на уровне хранилища или сервиса.
Необходимо добавить метод в IVersionStorage для выполнения операций в рамках одной транзакции, либо передавать объект транзакции в методы.
```
// В IVersionStorage добавить метод
func (s *GormStorage) WithTransaction(fn func(tx *GormStorage) error) error {
return s.db.Transaction(func(tx *gorm.DB) error {
return fn(&GormStorage{db: tx})
})
}
// В service/version.go
if count >= s.snapshotInterval {
full, err := s.ReconstructVersion(newVer.ID)
if err == nil {
err := s.storage.WithTransaction(func(txStore *store.IVersionStorage) error {
snapVer := models.Version{
ID: uuid.New(),
DocumentID: docID,
ParentID: &newVer.ID,
IsSnapshot: true,
Snapshot: full,
CreatedAt: time.Now(),
}
if err := txStore.CreateVersion(&snapVer); err != nil {
return err
}
return txStore.UpdateLatestVersion(docID, snapVer.ID)
})
if err != nil {
// log error
}
}
}
}
```
---
<sub><sup>Автоматическая проверка commit-keeper · модель `gemma4:31b` · `sha=488f11b`</sup></sub>
<!-- commit-keeper -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Severity: major
Commit:
488f11b— alphaЗатронутые места:
service/version.goстроки 135–156В чём проблема
Отсутствие атомарности при создании snapshot-версии. Операции CreateVersion и UpdateLatestVersion выполняются без транзакции. Если вторая операция завершится ошибкой, в базе останется 'сиротская' версия, а документ будет ссылаться на старую версию, что нарушает консистентность данных.
Цитата кода
Как исправить
Вариант 1 — Обернуть операции в транзакцию на уровне хранилища или сервиса.
Необходимо добавить метод в IVersionStorage для выполнения операций в рамках одной транзакции, либо передавать объект транзакции в методы.
Автоматическая проверка commit-keeper · модель
gemma4:31b·sha=488f11b