PageRenderTime 42ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/mordor/streams/fd.cpp

http://github.com/mozy/mordor
C++ | 235 lines | 214 code | 20 blank | 1 comment | 39 complexity | ed32d96e4eff3a1ecf1f6ce0e8f2da9e MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2009 - Mozy, Inc.
  2. #include "mordor/pch.h"
  3. #include "fd.h"
  4. #include <algorithm>
  5. #include <limits>
  6. #include <sys/fcntl.h>
  7. #include <sys/stat.h>
  8. #include <sys/uio.h>
  9. #include "buffer.h"
  10. #include "mordor/assert.h"
  11. #include "mordor/iomanager.h"
  12. namespace Mordor {
  13. static Logger::ptr g_log = Log::lookup("mordor:streams:fd");
  14. FDStream::FDStream()
  15. : m_ioManager(NULL),
  16. m_scheduler(NULL),
  17. m_fd(-1),
  18. m_own(false)
  19. {}
  20. void
  21. FDStream::init(int fd, IOManager *ioManager, Scheduler *scheduler, bool own)
  22. {
  23. MORDOR_ASSERT(fd >= 0);
  24. m_ioManager = ioManager;
  25. m_scheduler = scheduler;
  26. m_fd = fd;
  27. m_own = own;
  28. if (m_ioManager) {
  29. if (fcntl(m_fd, F_SETFL, O_NONBLOCK)) {
  30. error_t error = lastError();
  31. if (own) {
  32. ::close(m_fd);
  33. m_fd = -1;
  34. }
  35. MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "fcntl");
  36. }
  37. }
  38. }
  39. FDStream::~FDStream()
  40. {
  41. if (m_own && m_fd >= 0) {
  42. SchedulerSwitcher switcher(m_scheduler);
  43. int rc = ::close(m_fd);
  44. MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this
  45. << " close(" << m_fd << "): " << rc << " (" << lastError() << ")";
  46. }
  47. }
  48. void
  49. FDStream::close(CloseType type)
  50. {
  51. MORDOR_ASSERT(type == BOTH);
  52. if (m_fd > 0 && m_own) {
  53. SchedulerSwitcher switcher(m_scheduler);
  54. int rc = ::close(m_fd);
  55. error_t error = lastError();
  56. MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this
  57. << " close(" << m_fd << "): " << rc << " (" << error << ")";
  58. if (rc)
  59. MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "close");
  60. m_fd = -1;
  61. }
  62. }
  63. size_t
  64. FDStream::read(Buffer &buffer, size_t length)
  65. {
  66. SchedulerSwitcher switcher(m_ioManager ? NULL : m_scheduler);
  67. MORDOR_ASSERT(m_fd >= 0);
  68. if (length > 0xfffffffe)
  69. length = 0xfffffffe;
  70. std::vector<iovec> iovs = buffer.writeBuffers(length);
  71. int rc = readv(m_fd, &iovs[0], iovs.size());
  72. while (rc < 0 && errno == EAGAIN && m_ioManager) {
  73. MORDOR_LOG_TRACE(g_log) << this << " readv(" << m_fd << ", " << length
  74. << "): " << rc << " (EAGAIN)";
  75. m_ioManager->registerEvent(m_fd, IOManager::READ);
  76. Scheduler::yieldTo();
  77. rc = readv(m_fd, &iovs[0], iovs.size());
  78. }
  79. error_t error = lastError();
  80. MORDOR_LOG_LEVEL(g_log, rc < 0 ? Log::ERROR : Log::DEBUG) << this
  81. << " readv(" << m_fd << ", " << length << "): " << rc << " (" << error
  82. << ")";
  83. if (rc < 0)
  84. MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "readv");
  85. buffer.produce(rc);
  86. return rc;
  87. }
  88. size_t
  89. FDStream::read(void *buffer, size_t length)
  90. {
  91. SchedulerSwitcher switcher(m_ioManager ? NULL : m_scheduler);
  92. MORDOR_ASSERT(m_fd >= 0);
  93. if (length > 0xfffffffe)
  94. length = 0xfffffffe;
  95. int rc = ::read(m_fd, buffer, length);
  96. while (rc < 0 && errno == EAGAIN && m_ioManager) {
  97. MORDOR_LOG_TRACE(g_log) << this << " read(" << m_fd << ", " << length
  98. << "): " << rc << " (EAGAIN)";
  99. m_ioManager->registerEvent(m_fd, IOManager::READ);
  100. Scheduler::yieldTo();
  101. rc = ::read(m_fd, buffer, length);
  102. }
  103. error_t error = lastError();
  104. MORDOR_LOG_LEVEL(g_log, rc < 0 ? Log::ERROR : Log::DEBUG) << this
  105. << " read(" << m_fd << ", " << length << "): " << rc << " (" << error
  106. << ")";
  107. if (rc < 0)
  108. MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "read");
  109. return rc;
  110. }
  111. size_t
  112. FDStream::write(const Buffer &buffer, size_t length)
  113. {
  114. SchedulerSwitcher switcher(m_ioManager ? NULL : m_scheduler);
  115. MORDOR_ASSERT(m_fd >= 0);
  116. length = std::min(length, (size_t)std::numeric_limits<ssize_t>::max());
  117. const std::vector<iovec> iovs = buffer.readBuffers(length);
  118. ssize_t rc = 0;
  119. const int count = std::min(iovs.size(), (size_t)IOV_MAX);
  120. while ((rc = writev(m_fd, &iovs[0], count)) < 0 &&
  121. errno == EAGAIN && m_ioManager) {
  122. MORDOR_LOG_TRACE(g_log) << this << " writev(" << m_fd << ", " << length
  123. << "): " << rc << " (EAGAIN)";
  124. m_ioManager->registerEvent(m_fd, IOManager::WRITE);
  125. Scheduler::yieldTo();
  126. }
  127. error_t error = lastError();
  128. MORDOR_LOG_LEVEL(g_log, rc < 0 ? Log::ERROR : Log::DEBUG) << this
  129. << " writev(" << m_fd << ", " << length << "): " << rc << " (" << error
  130. << ")";
  131. if (rc == 0)
  132. MORDOR_THROW_EXCEPTION(std::runtime_error("Zero length write"));
  133. if (rc < 0)
  134. MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "writev");
  135. return rc;
  136. }
  137. size_t
  138. FDStream::write(const void *buffer, size_t length)
  139. {
  140. SchedulerSwitcher switcher(m_ioManager ? NULL : m_scheduler);
  141. MORDOR_ASSERT(m_fd >= 0);
  142. if (length > 0xfffffffe)
  143. length = 0xfffffffe;
  144. int rc = ::write(m_fd, buffer, length);
  145. while (rc < 0 && errno == EAGAIN && m_ioManager) {
  146. MORDOR_LOG_TRACE(g_log) << this << " write(" << m_fd << ", " << length
  147. << "): " << rc << " (EAGAIN)";
  148. m_ioManager->registerEvent(m_fd, IOManager::WRITE);
  149. Scheduler::yieldTo();
  150. rc = ::write(m_fd, buffer, length);
  151. }
  152. error_t error = lastError();
  153. MORDOR_LOG_LEVEL(g_log, rc < 0 ? Log::ERROR : Log::DEBUG) << this
  154. << " write(" << m_fd << ", " << length << "): " << rc << " (" << error
  155. << ")";
  156. if (rc == 0)
  157. MORDOR_THROW_EXCEPTION(std::runtime_error("Zero length write"));
  158. if (rc < 0)
  159. MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "write");
  160. return rc;
  161. }
  162. long long
  163. FDStream::seek(long long offset, Anchor anchor)
  164. {
  165. SchedulerSwitcher switcher(m_scheduler);
  166. MORDOR_ASSERT(m_fd >= 0);
  167. long long pos = lseek(m_fd, offset, (int)anchor);
  168. error_t error = lastError();
  169. MORDOR_LOG_LEVEL(g_log, pos < 0 ? Log::ERROR : Log::VERBOSE) << this
  170. << " lseek(" << m_fd << ", " << offset << ", " << anchor << "): "
  171. << pos << " (" << error << ")";
  172. if (pos < 0)
  173. MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "lseek");
  174. return pos;
  175. }
  176. long long
  177. FDStream::size()
  178. {
  179. SchedulerSwitcher switcher(m_scheduler);
  180. MORDOR_ASSERT(m_fd >= 0);
  181. struct stat statbuf;
  182. int rc = fstat(m_fd, &statbuf);
  183. error_t error = lastError();
  184. MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this
  185. << " fstat(" << m_fd << "): " << rc << " (" << error << ")";
  186. if (rc)
  187. MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "fstat");
  188. return statbuf.st_size;
  189. }
  190. void
  191. FDStream::truncate(long long size)
  192. {
  193. SchedulerSwitcher switcher(m_scheduler);
  194. MORDOR_ASSERT(m_fd >= 0);
  195. int rc = ftruncate(m_fd, size);
  196. error_t error = lastError();
  197. MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this
  198. << " ftruncate(" << m_fd << ", " << size << "): " << rc
  199. << " (" << error << ")";
  200. if (rc)
  201. MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "ftruncate");
  202. }
  203. void
  204. FDStream::flush(bool flushParent)
  205. {
  206. SchedulerSwitcher switcher(m_scheduler);
  207. MORDOR_ASSERT(m_fd >= 0);
  208. int rc = fsync(m_fd);
  209. error_t error = lastError();
  210. MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this
  211. << " fsync(" << m_fd << "): " << rc << " (" << error << ")";
  212. if (rc)
  213. MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "fsync");
  214. }
  215. }