@@ -58,7 +58,7 @@ const (
5858
5959// Pos represents the transactional position of a database.
6060type Pos struct {
61- TXID uint64
61+ TXID TXID
6262 PostApplyChecksum uint64
6363}
6464
@@ -75,7 +75,7 @@ func (p Pos) IsZero() bool {
7575// Marshal serializes the position into JSON.
7676func (p Pos ) MarshalJSON () ([]byte , error ) {
7777 var v posJSON
78- v .TXID = FormatTXID ( p .TXID )
78+ v .TXID = p .TXID . String ( )
7979 v .PostApplyChecksum = fmt .Sprintf ("%016x" , p .PostApplyChecksum )
8080 return json .Marshal (v )
8181}
@@ -116,6 +116,51 @@ func (e *PosMismatchError) Error() string {
116116 return fmt .Sprintf ("ltx position mismatch (%s)" , e .Pos )
117117}
118118
119+ // TXID represents a transaction ID.
120+ type TXID uint64
121+
122+ // ParseTXID parses a 16-character hex string into a transaction ID.
123+ func ParseTXID (s string ) (TXID , error ) {
124+ if len (s ) != 16 {
125+ return 0 , fmt .Errorf ("invalid formatted transaction id length: %q" , s )
126+ }
127+ v , err := strconv .ParseUint (s , 16 , 64 )
128+ if err != nil {
129+ return 0 , fmt .Errorf ("invalid transaction id format: %q" , s )
130+ }
131+ return TXID (v ), nil
132+ }
133+
134+ // String returns id formatted as a fixed-width hex number.
135+ func (t TXID ) String () string {
136+ return fmt .Sprintf ("%016x" , uint64 (t ))
137+ }
138+
139+ func (t TXID ) MarshalJSON () ([]byte , error ) {
140+ return []byte (`"` + t .String () + `"` ), nil
141+ }
142+
143+ func (t * TXID ) UnmarshalJSON (data []byte ) (err error ) {
144+ var s * string
145+ if err := json .Unmarshal (data , & s ); err != nil {
146+ return fmt .Errorf ("cannot unmarshal TXID from JSON value" )
147+ }
148+
149+ // Set to zero if value is nil.
150+ if s == nil {
151+ * t = 0
152+ return nil
153+ }
154+
155+ txID , err := ParseTXID (* s )
156+ if err != nil {
157+ return fmt .Errorf ("cannot parse TXID from JSON string: %q" , * s )
158+ }
159+ * t = TXID (txID )
160+
161+ return nil
162+ }
163+
119164// Header flags.
120165const (
121166 HeaderFlagMask = uint32 (0x00000001 )
@@ -129,8 +174,8 @@ type Header struct {
129174 Flags uint32 // reserved flags
130175 PageSize uint32 // page size, in bytes
131176 Commit uint32 // db size after transaction, in pages
132- MinTXID uint64 // minimum transaction ID
133- MaxTXID uint64 // maximum transaction ID
177+ MinTXID TXID // minimum transaction ID
178+ MaxTXID TXID // maximum transaction ID
134179 Timestamp int64 // milliseconds since unix epoch
135180 PreApplyChecksum uint64 // rolling checksum of database before applying this LTX file
136181 WALOffset int64 // file offset from original WAL; zero if journal
@@ -219,8 +264,8 @@ func (h *Header) MarshalBinary() ([]byte, error) {
219264 binary .BigEndian .PutUint32 (b [4 :], h .Flags )
220265 binary .BigEndian .PutUint32 (b [8 :], h .PageSize )
221266 binary .BigEndian .PutUint32 (b [12 :], h .Commit )
222- binary .BigEndian .PutUint64 (b [16 :], h .MinTXID )
223- binary .BigEndian .PutUint64 (b [24 :], h .MaxTXID )
267+ binary .BigEndian .PutUint64 (b [16 :], uint64 ( h .MinTXID ) )
268+ binary .BigEndian .PutUint64 (b [24 :], uint64 ( h .MaxTXID ) )
224269 binary .BigEndian .PutUint64 (b [32 :], uint64 (h .Timestamp ))
225270 binary .BigEndian .PutUint64 (b [40 :], h .PreApplyChecksum )
226271 binary .BigEndian .PutUint64 (b [48 :], uint64 (h .WALOffset ))
@@ -240,8 +285,8 @@ func (h *Header) UnmarshalBinary(b []byte) error {
240285 h .Flags = binary .BigEndian .Uint32 (b [4 :])
241286 h .PageSize = binary .BigEndian .Uint32 (b [8 :])
242287 h .Commit = binary .BigEndian .Uint32 (b [12 :])
243- h .MinTXID = binary .BigEndian .Uint64 (b [16 :])
244- h .MaxTXID = binary .BigEndian .Uint64 (b [24 :])
288+ h .MinTXID = TXID ( binary .BigEndian .Uint64 (b [16 :]) )
289+ h .MaxTXID = TXID ( binary .BigEndian .Uint64 (b [24 :]) )
245290 h .Timestamp = int64 (binary .BigEndian .Uint64 (b [32 :]))
246291 h .PreApplyChecksum = binary .BigEndian .Uint64 (b [40 :])
247292 h .WALOffset = int64 (binary .BigEndian .Uint64 (b [48 :]))
@@ -386,40 +431,23 @@ func ChecksumReader(r io.Reader, pageSize int) (uint64, error) {
386431 return chksum , nil
387432}
388433
389- // FormatTXID returns id formatted as a fixed-width hex number.
390- func FormatTXID (id uint64 ) string {
391- return fmt .Sprintf ("%016x" , id )
392- }
393-
394- // ParseTXID parses a 16-character hex string into a transaction ID.
395- func ParseTXID (s string ) (uint64 , error ) {
396- if len (s ) != 16 {
397- return 0 , fmt .Errorf ("invalid formatted transaction id length: %q" , s )
398- }
399- v , err := strconv .ParseUint (s , 16 , 64 )
400- if err != nil {
401- return 0 , fmt .Errorf ("invalid transaction id format: %q" , s )
402- }
403- return uint64 (v ), nil
404- }
405-
406434// ParseFilename parses a transaction range from an LTX file.
407- func ParseFilename (name string ) (minTXID , maxTXID uint64 , err error ) {
435+ func ParseFilename (name string ) (minTXID , maxTXID TXID , err error ) {
408436 a := filenameRegex .FindStringSubmatch (name )
409437 if a == nil {
410438 return 0 , 0 , fmt .Errorf ("invalid ltx filename: %s" , name )
411439 }
412440
413- minTXID , _ = strconv .ParseUint (a [1 ], 16 , 64 )
414- maxTXID , _ = strconv .ParseUint (a [2 ], 16 , 64 )
415- return minTXID , maxTXID , nil
441+ min , _ : = strconv .ParseUint (a [1 ], 16 , 64 )
442+ max , _ : = strconv .ParseUint (a [2 ], 16 , 64 )
443+ return TXID ( min ), TXID ( max ) , nil
416444}
417445
418446var filenameRegex = regexp .MustCompile (`^([0-9a-f]{16})-([0-9a-f]{16})\.ltx$` )
419447
420448// FormatFilename returns an LTX filename representing a range of transactions.
421- func FormatFilename (minTXID , maxTXID uint64 ) string {
422- return fmt .Sprintf ("%016x-%016x .ltx" , minTXID , maxTXID )
449+ func FormatFilename (minTXID , maxTXID TXID ) string {
450+ return fmt .Sprintf ("%s-%s .ltx" , minTXID . String () , maxTXID . String () )
423451}
424452
425453const PENDING_BYTE = 0x40000000
0 commit comments