第六节 WriteTo()和CopyFile()实现
1. // WriteTo writes the entire database to a writer.
2. // If err == nil then exactly tx.Size() bytes will be written into the writer.
3. func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
4. // Attempt to open reader with WriteFlag
5. f, err := os.OpenFile(tx.db.path, os.O_RDONLY|tx.WriteFlag, 0)
6. if err != nil {
7. return 0, err
8. }
9. defer func() { _ = f.Close() }()
11. // Generate a meta page. We use the same page data for both meta pages.
12. buf := make([]byte, tx.db.pageSize)
13. page := (*page)(unsafe.Pointer(&buf[0]))
14. page.flags = metaPageFlag
15. *page.meta() = *tx.meta
17. // Write meta 0.
18. page.id = 0
19. page.meta().checksum = page.meta().sum64()
20. nn, err := w.Write(buf)
21. n += int64(nn)
22. if err != nil {
23. return n, fmt.Errorf("meta 0 copy: %s", err)
24. }
26. // Write meta 1 with a lower transaction id.
27. page.id = 1
28. page.meta().txid -= 1
29. page.meta().checksum = page.meta().sum64()
30. nn, err = w.Write(buf)
31. n += int64(nn)
32. if err != nil {
33. return n, fmt.Errorf("meta 1 copy: %s", err)
34. }
36. // Move past the meta pages in the file.
37. if _, err := f.Seek(int64(tx.db.pageSize*2), os.SEEK_SET); err != nil {
38. return n, fmt.Errorf("seek: %s", err)
39. }
41. // Copy data pages.
42. wn, err := io.CopyN(w, f, tx.Size()-int64(tx.db.pageSize*2))
43. n += wn
44. if err != nil {
45. return n, err
46. }
48. return n, f.Close()
49. }
51. // CopyFile copies the entire database to file at the given path.
52. // A reader transaction is maintained during the copy so it is safe to continue
53. // using the database while a copy is in progress.
54. func (tx *Tx) CopyFile(path string, mode os.FileMode) error {
55. f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode)
56. if err != nil {
57. return err
58. }
60. err = tx.Copy(f)
61. if err != nil {
62. _ = f.Close()
63. return err
64. }
65. return f.Close()
66. }