SaveTo writes f's state to the given stream.
(ctx context.Context, w io.Writer, opts *SaveOpts)
| 97 | |
| 98 | // SaveTo writes f's state to the given stream. |
| 99 | func (f *MemoryFile) SaveTo(ctx context.Context, w io.Writer, opts *SaveOpts) error { |
| 100 | if err := f.AwaitLoadAll(); err != nil { |
| 101 | return fmt.Errorf("previous async page loading failed: %w", err) |
| 102 | } |
| 103 | |
| 104 | // Wait for memory release. |
| 105 | f.mu.Lock() |
| 106 | defer f.mu.Unlock() |
| 107 | for f.haveWaste { |
| 108 | f.mu.Unlock() |
| 109 | runtime.Gosched() |
| 110 | f.mu.Lock() |
| 111 | } |
| 112 | |
| 113 | // Ensure that there are no pending evictions. |
| 114 | if len(f.evictable) != 0 { |
| 115 | panic(fmt.Sprintf("evictions still pending for %d users; call StartEvictions and WaitForEvictions before SaveTo", len(f.evictable))) |
| 116 | } |
| 117 | |
| 118 | // Register this MemoryFile with async page saving if a pages file has been |
| 119 | // provided. |
| 120 | var amfs *asyncMemoryFileSave |
| 121 | if opts.PagesFile != nil { |
| 122 | var sf stateio.SourceFile |
| 123 | if opts.PagesFile.aw.NeedRegisterSourceFD() { |
| 124 | fileSize := uint64(len(f.chunksLoad())) * chunkSize |
| 125 | var err error |
| 126 | sf, err = opts.PagesFile.aw.RegisterSourceFD(int32(f.file.Fd()), fileSize, f.getClientFileRangeSettings(fileSize)) |
| 127 | if err != nil { |
| 128 | return fmt.Errorf("failed to register MemoryFile with pages file: %w", err) |
| 129 | } |
| 130 | } |
| 131 | amfs = &asyncMemoryFileSave{ |
| 132 | f: f, |
| 133 | pf: opts.PagesFile, |
| 134 | sf: sf, |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | // We only want to explicitly include pages containing non-zero bytes in |
| 139 | // the checkpoint, to reduce the size of the checkpoint and improve restore |
| 140 | // performance. Scan pages for non-zero bytes and ensure that they are |
| 141 | // marked known-committed. |
| 142 | // |
| 143 | // If async page saving is enabled, emit writes to the pages file during |
| 144 | // scanning, which is feasible since the pages metadata file and pages file |
| 145 | // are distinct. If async page saving is disabled, we can't do this since |
| 146 | // pages would be written to the state file before the metadata needed to |
| 147 | // determine where to load them to. (We could instead emit one memAcct |
| 148 | // segment at a time, immediately before the contents of the pages it |
| 149 | // represents. However, each call to state.Save() writes some overhead |
| 150 | // (header and type information), which would bloat the state file and slow |
| 151 | // down loading when the number of memAcct segments is large.) |
| 152 | timeScanStart := gohacks.Nanotime() |
| 153 | var ( |
| 154 | allocatedBytes uint64 |
| 155 | alreadyCommittedBytes uint64 |
| 156 | newCommittedBytes uint64 |
nothing calls this directly
no test coverage detected