freezer_utils.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // Copyright 2022 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package rawdb
  17. import (
  18. "io"
  19. "os"
  20. "path/filepath"
  21. )
  22. // copyFrom copies data from 'srcPath' at offset 'offset' into 'destPath'.
  23. // The 'destPath' is created if it doesn't exist, otherwise it is overwritten.
  24. // Before the copy is executed, there is a callback can be registered to
  25. // manipulate the dest file.
  26. // It is perfectly valid to have destPath == srcPath.
  27. func copyFrom(srcPath, destPath string, offset uint64, before func(f *os.File) error) error {
  28. // Create a temp file in the same dir where we want it to wind up
  29. f, err := os.CreateTemp(filepath.Dir(destPath), "*")
  30. if err != nil {
  31. return err
  32. }
  33. fname := f.Name()
  34. // Clean up the leftover file
  35. defer func() {
  36. if f != nil {
  37. f.Close()
  38. }
  39. os.Remove(fname)
  40. }()
  41. // Apply the given function if it's not nil before we copy
  42. // the content from the src.
  43. if before != nil {
  44. if err := before(f); err != nil {
  45. return err
  46. }
  47. }
  48. // Open the source file
  49. src, err := os.Open(srcPath)
  50. if err != nil {
  51. return err
  52. }
  53. if _, err = src.Seek(int64(offset), 0); err != nil {
  54. src.Close()
  55. return err
  56. }
  57. // io.Copy uses 32K buffer internally.
  58. _, err = io.Copy(f, src)
  59. if err != nil {
  60. src.Close()
  61. return err
  62. }
  63. // Rename the temporary file to the specified dest name.
  64. // src may be same as dest, so needs to be closed before
  65. // we do the final move.
  66. src.Close()
  67. if err := f.Close(); err != nil {
  68. return err
  69. }
  70. f = nil
  71. if err := os.Rename(fname, destPath); err != nil {
  72. return err
  73. }
  74. return nil
  75. }
  76. // openFreezerFileForAppend opens a freezer table file and seeks to the end
  77. func openFreezerFileForAppend(filename string) (*os.File, error) {
  78. // Open the file without the O_APPEND flag
  79. // because it has differing behaviour during Truncate operations
  80. // on different OS's
  81. file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0644)
  82. if err != nil {
  83. return nil, err
  84. }
  85. // Seek to end for append
  86. if _, err = file.Seek(0, io.SeekEnd); err != nil {
  87. return nil, err
  88. }
  89. return file, nil
  90. }
  91. // openFreezerFileForReadOnly opens a freezer table file for read only access
  92. func openFreezerFileForReadOnly(filename string) (*os.File, error) {
  93. return os.OpenFile(filename, os.O_RDONLY, 0644)
  94. }
  95. // openFreezerFileTruncated opens a freezer table making sure it is truncated
  96. func openFreezerFileTruncated(filename string) (*os.File, error) {
  97. return os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
  98. }
  99. // truncateFreezerFile resizes a freezer table file and seeks to the end
  100. func truncateFreezerFile(file *os.File, size int64) error {
  101. if err := file.Truncate(size); err != nil {
  102. return err
  103. }
  104. // Seek to end for append
  105. if _, err := file.Seek(0, io.SeekEnd); err != nil {
  106. return err
  107. }
  108. return nil
  109. }