writeCompleteIndex writes metadata and all records atomically via temp file + rename.
(records []IndexUserRecord)
| 477 | |
| 478 | // writeCompleteIndex writes metadata and all records atomically via temp file + rename. |
| 479 | func (idx *UserIndex) writeCompleteIndex(records []IndexUserRecord) error { |
| 480 | tmpFile := idx.Filename + ".tmp" |
| 481 | f, err := os.Create(tmpFile) |
| 482 | if err != nil { |
| 483 | return err |
| 484 | } |
| 485 | |
| 486 | writeErr := func() error { |
| 487 | headerBytes, err := idx.metaData.Format() |
| 488 | if err != nil { |
| 489 | return err |
| 490 | } |
| 491 | |
| 492 | buf := make([]byte, 0, len(headerBytes)+len(records)*IndexRecordSizeV1) |
| 493 | buf = append(buf, headerBytes...) |
| 494 | |
| 495 | var recBuf [IndexRecordSizeV1]byte |
| 496 | for _, rec := range records { |
| 497 | copy(recBuf[:80], rec.Username[:]) |
| 498 | binary.LittleEndian.PutUint64(recBuf[80:88], uint64(rec.UserID)) |
| 499 | recBuf[88] = IndexLineTerminatorV1 |
| 500 | buf = append(buf, recBuf[:]...) |
| 501 | } |
| 502 | |
| 503 | if _, err := f.Write(buf); err != nil { |
| 504 | return err |
| 505 | } |
| 506 | |
| 507 | return f.Sync() |
| 508 | }() |
| 509 | |
| 510 | if closeErr := f.Close(); writeErr == nil { |
| 511 | writeErr = closeErr |
| 512 | } |
| 513 | |
| 514 | if writeErr != nil { |
| 515 | os.Remove(tmpFile) |
| 516 | return writeErr |
| 517 | } |
| 518 | |
| 519 | return os.Rename(tmpFile, idx.Filename) |
| 520 | } |