Download this file
| 1 | package hostfloor |
| 2 | |
| 3 | import ( |
| 4 | "encoding/json" |
| 5 | "os" |
| 6 | "path/filepath" |
| 7 | ) |
| 8 | |
| 9 | // Begun is root's update-begun marker for a floor transaction. Begin writes |
| 10 | // it with the reservation ID before the first box-changing step. RolledBack |
| 11 | // is set by the backward paths before the journal is removed, so completion |
| 12 | // can tell a finished rollback from a transaction that never changed the box |
| 13 | // (Opus re-review M1-4). |
| 14 | type Begun struct { |
| 15 | ID string `json:"id"` |
| 16 | RolledBack bool `json:"rolled_back,omitempty"` |
| 17 | } |
| 18 | |
| 19 | // ReadBegun reads the marker in dir. An absent marker is os.ErrNotExist; one |
| 20 | // that does not decode or names no transaction is ErrFloor. |
| 21 | func ReadBegun(dir string) (Begun, error) { |
| 22 | raw, err := os.ReadFile(filepath.Join(dir, "update-begun.json")) |
| 23 | if err != nil { |
| 24 | return Begun{}, err |
| 25 | } |
| 26 | var b Begun |
| 27 | if json.Unmarshal(raw, &b) != nil || b.ID == "" { |
| 28 | return Begun{}, ErrFloor |
| 29 | } |
| 30 | return b, nil |
| 31 | } |
| 32 | |
| 33 | // MarkRolledBack records durably that transaction id rolled back. It never |
| 34 | // creates a marker: an absent one is os.ErrNotExist, and a marker for any |
| 35 | // other transaction is ErrFloor and is left as it is. |
| 36 | func MarkRolledBack(dir, id string) error { |
| 37 | b, err := ReadBegun(dir) |
| 38 | if err != nil { |
| 39 | return err |
| 40 | } |
| 41 | if b.ID != id { |
| 42 | return ErrFloor |
| 43 | } |
| 44 | if b.RolledBack { |
| 45 | return nil |
| 46 | } |
| 47 | b.RolledBack = true |
| 48 | raw, err := json.Marshal(b) |
| 49 | if err != nil { |
| 50 | return err |
| 51 | } |
| 52 | return Durable(filepath.Join(dir, "update-begun.json"), raw, 0644) |
| 53 | } |
| 54 | |