Class: HotCell::Output

Inherits:
Descriptor show all
Defined in:
lib/hot_cell/descriptors.rb

Constant Summary collapse

ACCESS_MODE =
Fcntl::O_WRONLY

Constants inherited from Descriptor

Descriptor::MODES

Instance Attribute Summary

Attributes inherited from Descriptor

#io

Instance Method Summary collapse

Methods inherited from Descriptor

#close, #fd_path, #initialize, #staged?, #to_io

Constructor Details

This class inherits a constructor from HotCell::Descriptor

Instance Method Details

#adopt(staged) ⇒ Object

Renames a staged sibling onto path, so post ships it. A sibling the tool never wrote is left to post's zero-byte accounting.



131
132
133
# File 'lib/hot_cell/descriptors.rb', line 131

def adopt(staged)
  File.rename staged, path if File.exist?(staged)
end

#path(extension: nil) ⇒ Object

Names the file the operation is to write, on the first call. Nothing is copied yet: post sends the file back out through the descriptor, and an operation that writes the descriptor directly never names one at all.

extension names a suffixed sibling on the same scratch instead, for a producer that picks its saver from the extension (ImageProcessing) or appends one of its own (pdftoppm). The sibling is not what post ships: adopt renames it into place.



124
125
126
127
# File 'lib/hot_cell/descriptors.rb', line 124

def path(extension: nil)
  base = (@path ||= scratch_path)
  extension.nil? ? base : "#{base}.#{extension}"
end

#postObject

Sends whatever the operation produced back out through the descriptor, and returns the byte count the cold side can now read. Outputs are posted and flushed before success is reported, so a caller may read as soon as it sees ok.

Two shapes, and an operation chooses by which path it wrote. A staged output was written to path on scratch and is copied out here; a file that does not exist means the operation wrote nothing, reported as zero the way a full tmpfs is. An output the operation wrote straight through the descriptor was never staged, so there is nothing to copy — the bytes are already in the caller's file — and this only flushes and measures. The direct form leaves partial bytes in the caller's file if the operation fails mid-write, where the staged form leaves it empty; every operation that writes directly turns a failure into a refusal the caller acts on rather than reading those bytes as a result.



146
147
148
149
150
151
152
153
154
155
# File 'lib/hot_cell/descriptors.rb', line 146

def post
  if staged?
    return 0 unless File.exist?(path)

    File.open(path, "rb") { |file| IO.copy_stream(file, io) }.tap { io.flush }
  else
    io.flush
    io.stat.size
  end
end