mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
Aside from improving checkpointing performance by using AIO to better utilize disk bandwidth, this makes it possible to parallelize writing pages with scanning for zero pages (in a following CL). As part of this, update and document ownership semantics for the state file, pages metadata file, and pages file, with the following goals: - Since io.WriteCloser.Close() may flush buffers, it must return a nil error before write success is reported - The pages metadata file is closed while async page saving is in progress (to hide the latency of the former) PiperOrigin-RevId: 814315485
132 lines
3.9 KiB
Go
132 lines
3.9 KiB
Go
// Copyright 2025 The gVisor Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package stateio
|
|
|
|
import (
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// This file contains utilities for implementors of AsyncReader and
|
|
// AsyncWriter.
|
|
|
|
// NoRegisterClientFD implements AsyncReader.NeedRegisterDestinationFD,
|
|
// AsyncReader.RegisterDestinationFD, AsyncWriter.NeedRegisterSourceFD, and
|
|
// AsyncWriter.RegisterSourceFD for implementations of AsyncReader and
|
|
// AsyncWriter that don't require client FD registration.
|
|
type NoRegisterClientFD struct{}
|
|
|
|
// NeedRegisterDestinationFD implements AsyncReader.NeedRegisterDestinationFD.
|
|
func (NoRegisterClientFD) NeedRegisterDestinationFD() bool {
|
|
return false
|
|
}
|
|
|
|
// RegisterDestinationFD implements AsyncReader.RegisterDestinationFD.
|
|
func (NoRegisterClientFD) RegisterDestinationFD(fd int32, size uint64, settings []ClientFileRangeSetting) (DestinationFile, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
// NeedRegisterSourceFD implements AsyncWriter.NeedRegisterSourceFD.
|
|
func (NoRegisterClientFD) NeedRegisterSourceFD() bool {
|
|
return false
|
|
}
|
|
|
|
// RegisterSourceFD implements AsyncWriter.RegisterSourceFD.
|
|
func (NoRegisterClientFD) RegisterSourceFD(fd int32, size uint64, settings []ClientFileRangeSetting) (SourceFile, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
// LocalClientRanges holds mappings as passed to AsyncReader.AddRead,
|
|
// AsyncReader.AddReadv, AsyncWriter.AddWrite, or AsyncWriter.AddWritev, for
|
|
// use by implementations that ignore the Destination/SourceFile and FileRanges
|
|
// and instead use only the provided mappings.
|
|
type LocalClientRanges struct {
|
|
// At most one of the following is non-nil:
|
|
Mapping []byte
|
|
Iovecs []unix.Iovec
|
|
}
|
|
|
|
// LocalClientMapping returns a LocalClientRanges representing the given
|
|
// mapping.
|
|
func LocalClientMapping(m []byte) LocalClientRanges {
|
|
return LocalClientRanges{Mapping: m}
|
|
}
|
|
|
|
// LocalClientMappings returns a LocalClientRanges representing the given
|
|
// mappings.
|
|
func LocalClientMappings(iovecs []unix.Iovec) LocalClientRanges {
|
|
return LocalClientRanges{Iovecs: iovecs}
|
|
}
|
|
|
|
// NumMappings returns the number of mappings represented by r.
|
|
func (r *LocalClientRanges) NumMappings() int {
|
|
if r.Mapping != nil {
|
|
return 1
|
|
}
|
|
return len(r.Iovecs)
|
|
}
|
|
|
|
// Mappings iterates the mappings represented by r.
|
|
func (r *LocalClientRanges) Mappings(yield func(i int, m []byte) bool) {
|
|
if r.Mapping != nil {
|
|
yield(0, r.Mapping)
|
|
return
|
|
}
|
|
for i, iov := range r.Iovecs {
|
|
if !yield(i, SliceFromIovec(iov)) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// DropFirst returns a LocalClientRanges equivalent to r, but with the first n
|
|
// bytes omitted. If n >= the total number of bytes in r, DropFirst returns a
|
|
// LocalClientRanges representing no mappings.
|
|
func (r *LocalClientRanges) DropFirst(n uint64) (r2 LocalClientRanges) {
|
|
for i, m := range r.Mappings {
|
|
if uint64(len(m)) <= n {
|
|
n -= uint64(len(m))
|
|
continue
|
|
}
|
|
m = m[n:]
|
|
n = 0
|
|
if r2.Iovecs == nil && i+1 == r.NumMappings() {
|
|
r2.Mapping = m
|
|
return
|
|
}
|
|
r2.Iovecs = append(r2.Iovecs, unix.Iovec{
|
|
Base: &m[0],
|
|
Len: uint64(len(m)),
|
|
})
|
|
}
|
|
return
|
|
}
|
|
|
|
// CompletionChanWait implements AsyncReader.Wait by receiving from a channel
|
|
// of completions.
|
|
func CompletionChanWait(ch <-chan Completion, cs []Completion, minCompletions int) ([]Completion, error) {
|
|
for minCompletions > 0 {
|
|
cs = append(cs, <-ch)
|
|
minCompletions--
|
|
}
|
|
for {
|
|
select {
|
|
case c := <-ch:
|
|
cs = append(cs, c)
|
|
default:
|
|
return cs, nil
|
|
}
|
|
}
|
|
}
|