XRootD
TPC::Stream Class Reference

#include <XrdHttpTpcStream.hh>

+ Collaboration diagram for TPC::Stream:

Public Member Functions

 Stream (std::unique_ptr< XrdSfsFile > fh, size_t max_blocks, size_t buffer_size, XrdSysError &log)
 
 ~Stream ()
 
size_t AvailableBuffers () const
 
void DumpBuffers () const
 
bool Finalize ()
 
std::string GetErrorMessage () const
 
int Read (off_t offset, char *buffer, size_t size)
 
int Stat (struct stat *)
 
ssize_t Write (off_t offset, const char *buffer, size_t size, bool force)
 

Detailed Description

Definition at line 23 of file XrdHttpTpcStream.hh.

Constructor & Destructor Documentation

◆ Stream()

TPC::Stream::Stream ( std::unique_ptr< XrdSfsFile fh,
size_t  max_blocks,
size_t  buffer_size,
XrdSysError log 
)
inline

Definition at line 25 of file XrdHttpTpcStream.hh.

26  : m_open_for_write(false),
27  m_avail_count(max_blocks),
28  m_fh(std::move(fh)),
29  m_offset(0),
30  m_log(log)
31  {
32  m_buffers.reserve(max_blocks);
33  for (size_t idx=0; idx < max_blocks; idx++) {
34  m_buffers.push_back(std::make_unique<Entry>(buffer_size));
35  }
36  m_open_for_write = true;
37  }

◆ ~Stream()

Stream::~Stream ( )

Definition at line 11 of file XrdHttpTpcStream.cc.

12 {
13  m_fh->close();
14 }

Member Function Documentation

◆ AvailableBuffers()

size_t TPC::Stream::AvailableBuffers ( ) const
inline

Definition at line 57 of file XrdHttpTpcStream.hh.

57 {return m_avail_count;}

Referenced by TPC::State::AvailableBuffers().

+ Here is the caller graph for this function:

◆ DumpBuffers()

void Stream::DumpBuffers ( ) const

Definition at line 208 of file XrdHttpTpcStream.cc.

209 {
210  m_log.Emsg("Stream::DumpBuffers", "Beginning dump of stream buffers.");
211  {
212  std::stringstream ss;
213  ss << "Stream offset: " << m_offset;
214  m_log.Emsg("Stream::DumpBuffers", ss.str().c_str());
215  }
216  size_t idx = 0;
217  for (const auto &entry : m_buffers) {
218  std::stringstream ss;
219  ss << "Buffer " << idx << ": Offset=" << entry->GetOffset() << ", Size="
220  << entry->GetSize() << ", Capacity=" << entry->GetCapacity();
221  m_log.Emsg("Stream::DumpBuffers", ss.str().c_str());
222  idx ++;
223  }
224  m_log.Emsg("Stream::DumpBuffers", "Finish dump of stream buffers.");
225 }
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95

References XrdSysError::Emsg().

Referenced by TPC::State::DumpBuffers(), and Write().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Finalize()

bool Stream::Finalize ( )

Definition at line 18 of file XrdHttpTpcStream.cc.

19 {
20  // Do not close twice
21  if (!m_open_for_write) {
22  return false;
23  }
24  m_open_for_write = false;
25 
26  // If there are outstanding buffers to reorder, finalization failed; the
27  // check has to happen before the buffers are released.
28  bool all_buffers_returned = m_avail_count == m_buffers.size();
29  m_buffers.clear();
30 
31  if (m_fh->close() == SFS_ERROR) {
32  std::stringstream ss;
33  const char *msg = m_fh->error.getErrText();
34  if (!msg || (*msg == '\0')) {msg = "(no error message provided)";}
35  ss << "Failure when closing file handle: " << msg << " (code=" << m_fh->error.getErrInfo() << ")";
36  m_error_buf = ss.str();
37  return false;
38  }
39 
40  return all_buffers_returned;
41 }
#define SFS_ERROR

References SFS_ERROR.

Referenced by TPC::State::Finalize().

+ Here is the caller graph for this function:

◆ GetErrorMessage()

std::string TPC::Stream::GetErrorMessage ( ) const
inline

Definition at line 70 of file XrdHttpTpcStream.hh.

70 {return m_error_buf;}

Referenced by TPC::State::Finalize(), and TPC::State::Flush().

+ Here is the caller graph for this function:

◆ Read()

int Stream::Read ( off_t  offset,
char *  buffer,
size_t  size 
)

Definition at line 229 of file XrdHttpTpcStream.cc.

230 {
231  return m_fh->read(offset, buf, size);
232 }

◆ Stat()

int Stream::Stat ( struct stat buf)

Definition at line 45 of file XrdHttpTpcStream.cc.

46 {
47  return m_fh->stat(buf);
48 }

◆ Write()

ssize_t Stream::Write ( off_t  offset,
const char *  buffer,
size_t  size,
bool  force 
)

Definition at line 51 of file XrdHttpTpcStream.cc.

52 {
53 /*
54  * NOTE: these lines are useful for debuggin the state of the buffer
55  * management code; too expensive to compile in and have a runtime switch.
56  std::stringstream ss;
57  ss << "Offset=" << offset << ", Size=" << size << ", force=" << force;
58  m_log.Emsg("Stream::Write", ss.str().c_str());
59  DumpBuffers();
60 */
61  if (!m_open_for_write) {
62  if (!m_error_buf.size()) {m_error_buf = "Logic error: writing to a buffer not opened for write";}
63  return SFS_ERROR;
64  }
65  size_t bytes_accepted = 0;
66  ssize_t retval = size;
67  if (offset < m_offset) {
68  if (!m_error_buf.size()) {m_error_buf = "Logic error: writing to a prior offset";}
69  return SFS_ERROR;
70  }
71  // If this is write is appending to the stream and
72  // MB-aligned, then we write it to disk; otherwise, the
73  // data will be buffered.
74  if (offset == m_offset && (force || (size && !(size % (1024*1024))))) {
75  retval = WriteImpl(offset, buf, size);
76  bytes_accepted = retval;
77  // On failure, we don't care about flushing buffers from memory --
78  // the stream is now invalid.
79  if (retval < 0) {
80  return retval;
81  }
82  // If there are no in-use buffers, then we don't need to
83  // do any accounting.
84  if (m_avail_count == m_buffers.size()) {
85  return retval;
86  }
87  }
88  // Even if we already accepted the current data, always iterate through the
89  // buffers and try to write as much out to disk as possible.
90  //
91  // Accepting data can complete a buffer, and flushing a buffer advances
92  // m_offset, which can in turn let another buffer accept more data or become
93  // writable. Alternate between the two until neither makes progress. When
94  // size == 0 we force a flush even if things are not MB-aligned.
95  ssize_t buffers_flushed;
96  do {
97  bytes_accepted += AcceptIntoBuffers(offset + bytes_accepted,
98  buf + bytes_accepted,
99  size - bytes_accepted);
100  buffers_flushed = FlushBuffers(size == 0);
101  if (buffers_flushed == SFS_ERROR) {return SFS_ERROR;}
102  } while ((buffers_flushed > 0) && (bytes_accepted != size));
103 
104  if (bytes_accepted != size && size) { // No place for this data in the buffers currently in use
105  Entry *avail_entry = FirstAvailableBuffer();
106  if (!avail_entry) { // No available buffers to allocate; logic error, should not happen.
107  DumpBuffers();
108  m_error_buf = "No empty buffers available to place unordered data.";
109  return SFS_ERROR;
110  }
111  if (avail_entry->Accept(offset + bytes_accepted, buf + bytes_accepted, size - bytes_accepted) != size - bytes_accepted) { // Empty buffer cannot accept?!?
112  m_error_buf = "Empty re-ordering buffer was unable to to accept data; internal logic error.";
113  return SFS_ERROR;
114  }
115  // The buffer we just filled may already be complete and contiguous with
116  // m_offset; flush it now instead of waiting for a later callback to
117  // notice, as every curl handle may be idle by then.
118  if (FlushBuffers(false) == SFS_ERROR) {return SFS_ERROR;}
119  }
120 
121  // If we have low buffer occupancy, then release memory.
122  if ((m_buffers.size() > 2) && (m_avail_count * 2 > m_buffers.size())) {
123  for (auto &entry : m_buffers) {
124  entry->ShrinkIfUnused();
125  }
126  }
127 
128  return retval;
129 }
void DumpBuffers() const

References DumpBuffers(), and SFS_ERROR.

Referenced by TPC::State::Flush().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

The documentation for this class was generated from the following files: