github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/synchronization/rsync/receive.go (about) 1 package rsync 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "fmt" 8 "io" 9 10 "github.com/mutagen-io/mutagen/pkg/filesystem" 11 ) 12 13 // EnsureValid ensures that ReceiverState's invariants are respected. 14 func (s *ReceiverState) EnsureValid() error { 15 // A nil receiver state is valid. 16 if s == nil { 17 return nil 18 } 19 20 // We intentionally avoid sanity checking the received byte count for a 21 // particular path because the expected byte count is merely an estimate; 22 // the actual transmission of the file is always susceptible to concurrent 23 // modifications which may yield more bytes transmitted than expected. 24 25 // Sanity check path counts. 26 if s.ReceivedFiles > s.ExpectedFiles { 27 return errors.New("too many files received") 28 } 29 30 // Success. 31 return nil 32 } 33 34 // Receiver manages the streaming reception of multiple files. It should be used 35 // in conjunction with the Transmit function. 36 type Receiver interface { 37 // Receive processes a single message in a transmission stream. 38 Receive(*Transmission) error 39 // finalize indicates that the transmission stream is completed and that no 40 // more messages will be received. This may indicate the successful 41 // completion of transmission, but could also indicate that the stream has 42 // failed due to an error. In any case, the receiver should use it as an 43 // opportunity to close all internal resources. It must be safe to call 44 // finalize after an error is returned from Receive. 45 finalize() error 46 } 47 48 // Sinker provides the interface for a receiver to store incoming files. 49 type Sinker interface { 50 // Sink should return a new io.WriteCloser for staging the given path. Each 51 // result it returns will be closed before Sink is invoked again. 52 Sink(path string) (io.WriteCloser, error) 53 } 54 55 // emptyReadSeekCloser is an implementation of io.ReadSeekCloser that is empty. 56 type emptyReadSeekCloser struct { 57 *bytes.Reader 58 } 59 60 // newEmptyReadSeekCloser constructs a new empty io.ReadSeekCloser. 61 func newEmptyReadSeekCloser() io.ReadSeekCloser { 62 return &emptyReadSeekCloser{&bytes.Reader{}} 63 } 64 65 // Close implements io.Closer for emptyReadSeekCloser. 66 func (e *emptyReadSeekCloser) Close() error { 67 return nil 68 } 69 70 // receiver is a Receiver implementation that actually writes files to disk. 71 type receiver struct { 72 // root is the file root. 73 root string 74 // paths is the list of paths to receive. 75 paths []string 76 // signatures is the list of signatures corresponding to the bases for these 77 // paths. 78 signatures []*Signature 79 // opener is the filesystem opener used to open base files. 80 opener *filesystem.Opener 81 // sinker is the Sinker to use for staging files. 82 sinker Sinker 83 // engine is the rsync Engine. 84 engine *Engine 85 // received is the number of files received. 86 received uint64 87 // total is the total number of files to receive (the number of paths). 88 total uint64 89 // finalized indicates whether or not the receiver has been finalized. 90 finalized bool 91 // burning indicates that the receiver is currently burning operations due 92 // to a failed file receiving operation. 93 burning bool 94 // base is the base for the current file. It should be non-nil if and only 95 // if target is non-nil. It should be nil if burning. 96 base io.ReadSeekCloser 97 // target is the destination for the current file. It should be non-nil if 98 // and only if base is non-nil. It should be nil if burning. 99 target io.WriteCloser 100 } 101 102 // NewReceiver creates a new receiver that stores files on disk. It is the 103 // responsibility of the caller to ensure that the provided signatures are valid 104 // by invoking their EnsureValid method. In order for the receiver to perform 105 // efficiently, paths should be passed in depth-first traversal order. 106 func NewReceiver(root string, paths []string, signatures []*Signature, sinker Sinker) (Receiver, error) { 107 // Ensure that the receiving request is sane. 108 if len(paths) != len(signatures) { 109 return nil, errors.New("number of paths does not match number of signatures") 110 } 111 112 // Create the receiver. 113 return &receiver{ 114 root: root, 115 paths: paths, 116 signatures: signatures, 117 opener: filesystem.NewOpener(root), 118 sinker: sinker, 119 engine: NewEngine(), 120 total: uint64(len(paths)), 121 }, nil 122 } 123 124 // Receive processes incoming messages by storing files to disk. 125 func (r *receiver) Receive(transmission *Transmission) error { 126 // Check that we haven't been finalized. 127 if r.finalized { 128 panic("receive called on finalized receiver") 129 } 130 131 // Make sure that we're not seeing a transmission after receiving all files. 132 // If we are, it's a terminal error. 133 if r.received == r.total { 134 return errors.New("unexpected file transmission") 135 } 136 137 // Check if we need to skip this transmission due to burning. 138 skip := r.burning 139 140 // Check if this is a done transmission. 141 if transmission.Done { 142 // TODO: The transmission may have error information here. Should we 143 // expose that to whatever is doing the file sinking? It doesn't matter 144 // for our application since we have independent hash validation, but it 145 // might be useful for some cases. 146 147 // Close out base and target if they're open, because we're done with 148 // this file. If they're not open, and we're not burning, it means that 149 // we have an empty file. Since we won't have opened any sink for the 150 // file (no operations came in for it), open one quickly and close it. 151 // Since we're already at the end of the stream for this file, there's 152 // no need to start burning operations if this fails. 153 if r.base != nil { 154 r.base.Close() 155 r.base = nil 156 r.target.Close() 157 r.target = nil 158 } else if !r.burning { 159 if target, _ := r.sinker.Sink(r.paths[r.received]); target != nil { 160 target.Close() 161 } 162 } 163 164 // Update the received count. 165 r.received++ 166 167 // Reset burning status. 168 r.burning = false 169 170 // Skip the transmission (since it doesn't contain any operation). 171 skip = true 172 } 173 174 // Skip the transmission if necessary, either due to burning or the fact 175 // that it's a done transmission (or both). 176 if skip { 177 return nil 178 } 179 180 // Extract the signature for this file. 181 signature := r.signatures[r.received] 182 183 // Check if we are starting a new file stream and need to open the base and 184 // target. 185 if r.base == nil { 186 // Extract the path. 187 path := r.paths[r.received] 188 189 // Open the base. If the signature is a zero value, then we just use an 190 // empty base. If it's not, then we need to try to open the base. If 191 // that fails, then we need to burn this file stream, but it's not a 192 // terminal error. 193 if signature.isEmpty() { 194 r.base = newEmptyReadSeekCloser() 195 } else if base, _, err := r.opener.OpenFile(path); err != nil { 196 r.burning = true 197 return nil 198 } else { 199 r.base = base 200 } 201 202 // Create a sink. If that fails, then we need to close out the base and 203 // burn this file stream, but it's not a terminal error. 204 if target, err := r.sinker.Sink(path); err != nil { 205 r.base.Close() 206 r.base = nil 207 r.burning = true 208 return nil 209 } else { 210 r.target = target 211 } 212 } 213 214 // Apply the operation. If that fails, then we need to close out the base, 215 // target, and burn this file stream, but it's not a terminal error. 216 if err := r.engine.Patch(r.target, r.base, signature, transmission.Operation); err != nil { 217 r.base.Close() 218 r.base = nil 219 r.target.Close() 220 r.target = nil 221 r.burning = true 222 return nil 223 } 224 225 // Success. 226 return nil 227 } 228 229 // finalize aborts reception (if still in-progress) closes any open receiver 230 // resources. 231 func (r *receiver) finalize() error { 232 // Watch for double finalization. 233 if r.finalized { 234 return errors.New("receiver finalized multiple times") 235 } 236 237 // Close any open internal resources. 238 if r.base != nil { 239 r.base.Close() 240 r.base = nil 241 r.target.Close() 242 r.target = nil 243 } 244 245 // Close the file opener. 246 r.opener.Close() 247 248 // Mark the receiver as finalized. 249 r.finalized = true 250 251 // Success. 252 return nil 253 } 254 255 // Monitor is the interface that monitors must implement to capture state 256 // information from a monitoring receiver. The state object provided to this 257 // function must not be modified or retained. When the monitoring receiver is 258 // finalized, the Monitor callback will receive a nil state value. 259 type Monitor func(*ReceiverState) error 260 261 // monitoringReceiver is a Receiver implementation that can invoke a callback 262 // with information about the status of transmission. 263 type monitoringReceiver struct { 264 // receiver is the underlying receiver. 265 receiver Receiver 266 // paths is the list of paths the receiver is expecting. 267 paths []string 268 // signatures are the signatures corresponding to paths. 269 signatures []*Signature 270 // monitor is the monitoring callback. 271 monitor Monitor 272 // startOfFile tracks whether or not the next transmission in the stream is 273 // expected to coincide with the start of a new file. 274 startOfFile bool 275 // state is the current receiver state. 276 state *ReceiverState 277 } 278 279 // NewMonitoringReceiver wraps a receiver and provides monitoring information 280 // via a callback. 281 func NewMonitoringReceiver(receiver Receiver, paths []string, signatures []*Signature, monitor Monitor) Receiver { 282 // Verify that the path and signature counts match. 283 if len(paths) != len(signatures) { 284 panic("path count does not match signature count") 285 } 286 287 // Create the receiver. 288 return &monitoringReceiver{ 289 receiver: receiver, 290 paths: paths, 291 signatures: signatures, 292 monitor: monitor, 293 startOfFile: true, 294 state: &ReceiverState{ 295 ExpectedFiles: uint64(len(paths)), 296 }, 297 } 298 } 299 300 // Receive forwards messages to its underlying receiver and performs status 301 // updates by invoking the specified monitor. 302 func (r *monitoringReceiver) Receive(transmission *Transmission) error { 303 // Make sure that we're not seeing a transmission after receiving all files. 304 // If we are, then it's a terminal error. 305 if r.state.ReceivedFiles == r.state.ExpectedFiles { 306 return errors.New("unexpected file transmission") 307 } 308 309 // Forward the transmission to the underlying receiver. 310 if err := r.receiver.Receive(transmission); err != nil { 311 return err 312 } 313 314 // If we're at the start of a new file, then compute the path and reset the 315 // per-file statistics. 316 if r.startOfFile { 317 r.state.Path = r.paths[r.state.ReceivedFiles] 318 r.state.ReceivedSize = 0 319 r.state.ExpectedSize = transmission.ExpectedSize 320 } 321 322 // Compute the amount of data contained in this transmission. 323 var dataSize uint64 324 if !transmission.Done { 325 if d := len(transmission.Operation.Data); d > 0 { 326 dataSize = uint64(d) 327 } else { 328 signature := r.signatures[r.state.ReceivedFiles] 329 if transmission.Operation.Start+transmission.Operation.Count == uint64(len(signature.Hashes)) { 330 dataSize += (transmission.Operation.Count - 1) * signature.BlockSize 331 dataSize += signature.LastBlockSize 332 } else { 333 dataSize += transmission.Operation.Count * signature.BlockSize 334 } 335 } 336 } 337 338 // Update received data statistics. 339 r.state.ReceivedSize += dataSize 340 r.state.TotalReceivedSize += dataSize 341 342 // Provide the updated state to the monitor if relevant. 343 if !transmission.Done || r.startOfFile { 344 if err := r.monitor(r.state); err != nil { 345 return fmt.Errorf("unable to send receiver state: %w", err) 346 } 347 } 348 349 // If we're at the end of transmissions for the current file, then update 350 // the received file count. 351 if transmission.Done { 352 r.state.ReceivedFiles++ 353 } 354 355 // Update stream position tracking. 356 r.startOfFile = transmission.Done 357 358 // Success. 359 return nil 360 } 361 362 // finalize invokes finalize on the underlying receiver. It also performs a 363 // final empty status update, though it doesn't check for an error when doing 364 // so. 365 func (r *monitoringReceiver) finalize() error { 366 // Perform a final status update. We don't bother checking for an error 367 // because it's inconsequential at this point. 368 r.monitor(nil) 369 370 // Invoke finalize on the underlying receiver. 371 return r.receiver.finalize() 372 } 373 374 // preemptableReceiver is a Receiver implementation that provides preemption 375 // facilities. 376 type preemptableReceiver struct { 377 // ctx is the context in which the receiver is receiving. 378 ctx context.Context 379 // receiver is the underlying receiver. 380 receiver Receiver 381 } 382 383 // NewPreemptableReceiver wraps a receiver and aborts on Receive if the 384 // specified context has been cancelled. 385 func NewPreemptableReceiver(ctx context.Context, receiver Receiver) Receiver { 386 return &preemptableReceiver{ 387 ctx: ctx, 388 receiver: receiver, 389 } 390 } 391 392 // Receive performs a check for preemption, aborting if the receiver has been 393 // preempted. If no preemption has occurred, the transmission is forwarded to 394 // the underlying receiver. 395 func (r *preemptableReceiver) Receive(transmission *Transmission) error { 396 // Check for preemption in a non-blocking fashion. 397 select { 398 case <-r.ctx.Done(): 399 return errors.New("reception cancelled") 400 default: 401 } 402 403 // Forward the transmission. 404 return r.receiver.Receive(transmission) 405 } 406 407 // finalize invokes finalize on the underlying receiver. 408 func (r *preemptableReceiver) finalize() error { 409 return r.receiver.finalize() 410 } 411 412 // Encoder is the interface used by an encoding receiver to forward 413 // transmissions, usually across a network. 414 type Encoder interface { 415 // Encode encodes and transmits a transmission. The provided transmission 416 // will never be nil. The transmission passed to the encoder may be re-used 417 // and modified, so the encoder should not hold on to the transmission 418 // between calls (it should either transmit it or fully copy it if 419 // transmission is going to be delayed). 420 Encode(*Transmission) error 421 // Finalize is called when the transmission stream is finished. The Encoder 422 // can use this call to close any underlying transmission resources. 423 Finalize() error 424 } 425 426 // encodingReceiver is a Receiver implementation that encodes messages to an 427 // arbitrary encoder. 428 type encodingReceiver struct { 429 // encoder is the Encoder to use for encoding messages. 430 encoder Encoder 431 // finalized indicates whether or not the receiver has been finalized. 432 finalized bool 433 } 434 435 // NewEncodingReceiver creates a new receiver that handles messages by encoding 436 // them with the specified Encoder. It is designed to be used with 437 // DecodeToReceiver. 438 func NewEncodingReceiver(encoder Encoder) Receiver { 439 return &encodingReceiver{ 440 encoder: encoder, 441 } 442 } 443 444 // Receive encodes the specified transmission using the underlying encoder. 445 func (r *encodingReceiver) Receive(transmission *Transmission) error { 446 // Encode the transmission. 447 if err := r.encoder.Encode(transmission); err != nil { 448 return fmt.Errorf("unable to encode transmission: %w", err) 449 } 450 451 // Success. 452 return nil 453 } 454 455 // finalize finalizes the encoding receiver, which means that it calls Finalize 456 // on its underlying Encoder. 457 func (r *encodingReceiver) finalize() error { 458 // Watch for double finalization. 459 if r.finalized { 460 return errors.New("receiver finalized multiple times") 461 } 462 463 // Mark ourselves as finalized 464 r.finalized = true 465 466 // Finalize the encoder. 467 if err := r.encoder.Finalize(); err != nil { 468 return fmt.Errorf("unable to finalize encoder: %w", err) 469 } 470 471 // Success. 472 return nil 473 } 474 475 // Decoder is the interface used by DecodeToReceiver to receive transmissions, 476 // usually across a network. 477 type Decoder interface { 478 // Decoder decodes a transmission encoded by an encoder. The transmission 479 // should be decoded into the specified Transmission object, which will be a 480 // non-nil zero-valued Transmission object. The decoder is *not* responsible 481 // for validating that the transmission is valid before returning it. 482 // TODO: We should really elaborate on the semantics of Decoder, in 483 // particular how it is allowed to re-use existing allocations within the 484 // Transmission object. 485 Decode(*Transmission) error 486 // Finalize is called when decoding is finished. The Decoder can use this 487 // call to close any underlying transmission resources. 488 Finalize() error 489 } 490 491 // DecodeToReceiver decodes messages from the specified Decoder and forwards 492 // them to the specified receiver. It must be passed the number of files to be 493 // received so that it knows when forwarding is complete. It is designed to be 494 // used with an encoding receiver, such as that returned by NewEncodingReceiver. 495 // It finalizes the provided receiver before returning. 496 func DecodeToReceiver(decoder Decoder, count uint64, receiver Receiver) error { 497 // Allocate the transmission object that we'll use to receive into. 498 transmission := &Transmission{} 499 500 // Loop until we've seen all files come in. 501 for count > 0 { 502 // Loop, decode, and forward until we see a done message. 503 for { 504 // Receive the next message. 505 transmission.resetToZeroMaintainingCapacity() 506 if err := decoder.Decode(transmission); err != nil { 507 decoder.Finalize() 508 receiver.finalize() 509 return fmt.Errorf("unable to decode transmission: %w", err) 510 } 511 512 // Validate the transmission. 513 if err := transmission.EnsureValid(); err != nil { 514 decoder.Finalize() 515 receiver.finalize() 516 return fmt.Errorf("invalid transmission received: %w", err) 517 } 518 519 // Forward the message. 520 if err := receiver.Receive(transmission); err != nil { 521 decoder.Finalize() 522 receiver.finalize() 523 return fmt.Errorf("unable to forward message to receiver: %w", err) 524 } 525 526 // If the message indicates completion, we're done receiving 527 // messages for this file. 528 if transmission.Done { 529 break 530 } 531 } 532 533 // Update the count. 534 count-- 535 } 536 537 // Ensure that the decoder is finalized. 538 if err := decoder.Finalize(); err != nil { 539 receiver.finalize() 540 return fmt.Errorf("unable to finalize decoder: %w", err) 541 } 542 543 // Ensure that the receiver is finalized. 544 if err := receiver.finalize(); err != nil { 545 return fmt.Errorf("unable to finalize receiver: %w", err) 546 } 547 548 // Done. 549 return nil 550 }