mem_map_stream.cpp
上传用户:kx_jwh
上传日期:2021-09-03
资源大小:76k
文件大小:19k
源码类别:

STL

开发平台:

Visual C++

  1. /* vim: set tabstop=4 : */
  2. #include <assert.h>
  3. #include <string.h>
  4. #include <sstream>
  5. #include <stdexcept>
  6. #include "mem_map_stream.h"
  7. #include "IOException.h"
  8. #include "IStream.h"
  9. namespace febird {
  10. static void write_error_msg(std::ostringstream& oss)
  11. {
  12. #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
  13. int errCode = GetLastError();
  14. HLOCAL hLocal = NULL;
  15. DWORD dwTextLength = FormatMessageA(
  16. FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  17. NULL,
  18. errCode,
  19. 0, //MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
  20. (LPSTR)&hLocal,
  21. 0,
  22. NULL
  23. );
  24. LPCSTR pszMsg = (LPCSTR)LocalLock(hLocal);
  25. oss << "error[code=" << errCode << ", message=" << pszMsg << "]";
  26. LocalFree(hLocal);
  27. #else
  28. char szbuf[256];
  29. int  errCode = errno;
  30. strerror_r(errCode, szbuf, 256);
  31. oss << "error[code=" << errCode << ", message=" << szbuf << "]";
  32. #endif
  33. }
  34. static std::string error_info(const std::string& fpath, const char* uinfo)
  35. {
  36. std::ostringstream oss;
  37. oss << "file="" << fpath << """ << ", " << uinfo << " : ";
  38. write_error_msg(oss);
  39. return oss.str();
  40. }
  41. MMS_MapData::MMS_MapData(MemMapStream& mms, stream_position_t fpos, size_t size)
  42. : m_mms(&mms), m_size(size)
  43. {
  44. m_base_ptr = 0; // maybe failure, so first set to 0
  45. m_base_pos = align_down(fpos, mms.page_size());
  46. m_offset = fpos - m_base_pos;
  47. m_base_ptr = (unsigned char*)mms.map(m_base_pos, align_up(m_offset + size, mms.page_size()));
  48. }
  49. MMS_MapData::MMS_MapData(MemMapStream& mms, stream_position_t fpos, size_t size, int flag)
  50. : m_mms(&mms), m_size(size)
  51. {
  52. m_base_ptr = 0; // maybe failure, so first set to 0
  53. m_base_pos = align_down(fpos, mms.page_size());
  54. m_offset = fpos - m_base_pos;
  55. m_base_ptr = (unsigned char*)mms.map(m_base_pos, align_up(m_offset + size, mms.page_size()), flag);
  56. }
  57. MMS_MapData::~MMS_MapData()
  58. {
  59. if (m_base_ptr)
  60. m_mms->unmap(m_base_ptr, align_up(m_offset + m_size, m_mms->page_size()));
  61. }
  62. //////////////////////////////////////////////////////////////////////////
  63. MemMapStream::MemMapStream(stream_position_t new_file_size, const std::string& fpath, int mode)
  64. {
  65. init();
  66.     open(new_file_size, fpath, mode);
  67. }
  68. MemMapStream::MemMapStream()
  69. {
  70. init();
  71. }
  72. MemMapStream::~MemMapStream()
  73. {
  74. close();
  75. }
  76. void MemMapStream::init(stream_position_t new_file_size, const std::string& fpath, int mode)
  77. {
  78. init();
  79. m_file_size = new_file_size;
  80. m_fpath = fpath;
  81. m_mode = mode;
  82. }
  83. void MemMapStream::init()
  84. {
  85. #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
  86. m_hFile = INVALID_HANDLE_VALUE;
  87. m_hMap = 0;
  88. SYSTEM_INFO si;
  89. GetSystemInfo(&si); 
  90. m_page_size = si.dwPageSize;
  91. m_AllocationGranularity = si.dwAllocationGranularity;
  92. #else
  93. m_hFile = -1;
  94. m_page_size = sysconf(_SC_PAGESIZE);
  95. m_AllocationGranularity = m_page_size;
  96. #endif
  97. m_file_pos = 0;
  98. m_file_size = 0;
  99. m_beg = m_pos = m_end = 0;
  100. m_best_block_size = 256 * 1024;
  101. assert(m_best_block_size % m_AllocationGranularity == 0);
  102. }
  103. void MemMapStream::clone(const MemMapStream& source)
  104. {
  105. #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
  106. HANDLE hProcess = GetCurrentProcess();
  107. BOOL bRet = DuplicateHandle(
  108. hProcess,
  109. source.m_hFile,
  110. hProcess,
  111. &m_hFile,
  112. 0, //(m_mode & O_RDWR) ? GENERIC_ALL : GENERIC_READ,
  113. FALSE,
  114. DUPLICATE_SAME_ACCESS
  115. );
  116.     if (m_hFile == INVALID_HANDLE_VALUE)
  117.         cleanup_and_throw("failed on calling DuplicateHandle");
  118. m_hMap = 0;
  119. #else
  120. m_hFile = ::dup(source.m_hFile);
  121. #endif
  122. m_page_size = source.m_page_size;
  123. m_AllocationGranularity = source.m_AllocationGranularity;
  124. m_file_pos = 0;
  125. m_beg = m_pos = m_end = 0;
  126. m_best_block_size = source.m_best_block_size;
  127. m_fpath = source.m_fpath;
  128. }
  129. void* MemMapStream::map(stream_position_t fpos, size_t size)
  130. {
  131. return map(fpos, size, m_mode);
  132. }
  133. #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
  134. void* MemMapStream::map(stream_position_t fpos, size_t size, int mode)
  135. {
  136. if ((mode & O_RDWR) && m_file_size < fpos + size)
  137. {
  138. set_fsize(fpos + size);
  139. m_file_size = fpos + size;
  140. if (NULL != m_hMap)
  141. CloseHandle(m_hMap), m_hMap = NULL;
  142. }
  143. if (NULL == m_hMap)
  144. {
  145. m_hMap = CreateFileMapping(m_hFile
  146. , NULL
  147. , !(m_mode & O_RDWR) ? PAGE_READONLY : PAGE_READWRITE
  148. , 0
  149. , 0
  150. , NULL
  151. );
  152. if (NULL == m_hMap)
  153. cleanup_and_throw("failed CreateFileMapping");
  154. }
  155. void* base =
  156.         ::MapViewOfFileEx( m_hMap,
  157.    (mode & O_RDWR) ? FILE_MAP_WRITE : FILE_MAP_READ,
  158.                            (DWORD) (fpos >> 32),
  159.                            (DWORD) (fpos & 0xffffffff),
  160.                            size,
  161.    (LPVOID) 0
  162.    );
  163. if (0 == base)
  164. throw IOException(error_info(m_fpath, "failed MapViewOfFileEx").c_str());
  165.     return base;
  166. }
  167. void MemMapStream::unmap(void* base, size_t size)
  168. {
  169. ::UnmapViewOfFile(base);
  170. }
  171. void MemMapStream::open(stream_position_t new_file_size, const std::string& fpath, int mode)
  172. {
  173.     using namespace std;
  174.     if (is_open())
  175.         throw IOException("file already open");
  176. init(new_file_size, fpath, mode);
  177. bool readonly = !(m_mode & O_RDWR);
  178.     m_hFile = ::CreateFileA(fpath.c_str(),
  179.                        readonly ? GENERIC_READ : GENERIC_READ|GENERIC_WRITE,
  180.                        FILE_SHARE_READ,
  181.                        NULL,
  182.                        (m_mode & O_CREAT) ? 
  183.                            OPEN_ALWAYS : 
  184.                            OPEN_EXISTING,
  185.                        readonly ?
  186.                            FILE_ATTRIBUTE_READONLY :
  187.                            FILE_ATTRIBUTE_TEMPORARY,
  188.                        NULL);
  189.     if (m_hFile == INVALID_HANDLE_VALUE)
  190.         cleanup_and_throw("failed opening file");
  191.     if (m_mode & O_TRUNC)
  192. set_fsize(new_file_size);
  193. m_file_size = get_fsize();
  194. return;
  195. }
  196. stream_position_t MemMapStream::get_fsize()
  197. {
  198.     typedef BOOL (WINAPI *func)(HANDLE, PLARGE_INTEGER);
  199.     HMODULE hmod = ::GetModuleHandleA("kernel32.dll");
  200.     func fp_get_size =
  201.         reinterpret_cast<func>(::GetProcAddress(hmod, "GetFileSizeEx"));
  202.     if (fp_get_size) {
  203.         LARGE_INTEGER info;
  204.         if (fp_get_size(m_hFile, &info)) {
  205.             boost::uintmax_t fsize =
  206.                 ( (static_cast<boost::intmax_t>(info.HighPart) << 32) |
  207.                   info.LowPart );
  208.             return fsize;
  209.         } else {
  210.             cleanup_and_throw("failed getting file size");
  211.         }
  212.     } else {
  213.         DWORD hi;
  214.         DWORD low;
  215.         if ( (low = ::GetFileSize(m_hFile, &hi))
  216.                  !=
  217.              INVALID_FILE_SIZE )
  218.         {
  219.             boost::uintmax_t fsize =
  220.                 (static_cast<boost::intmax_t>(hi) << 32) | low;
  221.             return fsize;
  222.         } else {
  223.             cleanup_and_throw("failed getting file size");
  224.         }
  225.     }
  226. assert(0); // would not goes here...
  227. return 0;  // trim warning..
  228. }
  229. void MemMapStream::set_fsize(stream_position_t fsize)
  230. {
  231.     LONG sizehigh = LONG(fsize >> 32);
  232.     LONG sizelow = LONG(fsize & 0xffffffff);
  233.     ::SetFilePointer(m_hFile, sizelow, &sizehigh, FILE_BEGIN);
  234.     if (::GetLastError() != NO_ERROR || !::SetEndOfFile(m_hFile))
  235.         cleanup_and_throw("failed setting file size");
  236. m_file_size = fsize;
  237. }
  238. bool MemMapStream::remap_impl(stream_position_t fpos, size_t map_size)
  239. {
  240. bool readonly = !(m_mode & O_RDWR);
  241. if (m_beg)
  242. ::UnmapViewOfFile(m_beg);
  243. if (!readonly && m_file_size < fpos + map_size)
  244. {
  245. set_fsize(fpos + map_size);
  246. if (NULL != m_hMap)
  247. CloseHandle(m_hMap), m_hMap = NULL;
  248. }
  249. if (NULL == m_hMap)
  250. {
  251. m_hMap = CreateFileMapping(m_hFile
  252. , NULL
  253. , readonly ? PAGE_READONLY : PAGE_READWRITE
  254. , 0
  255. , 0
  256. , NULL
  257. );
  258. if (NULL == m_hMap)
  259. cleanup_and_throw("failed CreateFileMapping");
  260. }
  261.     m_beg = (unsigned char*)
  262.         ::MapViewOfFileEx( m_hMap,
  263.                            readonly ? FILE_MAP_READ : FILE_MAP_WRITE,
  264.                            (DWORD) (fpos >> 32),
  265.                            (DWORD) (fpos & 0xffffffff),
  266.                            map_size != size_t(-1L) ? map_size : 0, (LPVOID) 0 );
  267.     return 0 != m_beg;
  268. }
  269. bool MemMapStream::is_open() const throw()
  270. {
  271. return m_hFile != INVALID_HANDLE_VALUE;
  272. }
  273. #else // not windows
  274. void* MemMapStream::map(stream_position_t fpos, size_t size, int mode)
  275. {
  276. assert(fpos % m_AllocationGranularity == 0);
  277. if ((mode & O_RDWR) && m_file_size < fpos + size)
  278. {
  279. set_fsize(fpos + size);
  280. }
  281. // int flags = (mode & O_RDWR) ? MAP_SHARED : MAP_PRIVATE;
  282. int flags = MAP_SHARED;
  283. void* base = ::mmap(NULL, size,
  284.                          (mode & O_RDWR) ? (PROT_READ | PROT_WRITE) : PROT_READ,
  285.                          flags,
  286.                          m_hFile, fpos);
  287. if (MAP_FAILED == base)
  288. {
  289. throw IOException(error_info(m_fpath, "failed mmap").c_str());
  290. }
  291.     return base;
  292. }
  293. void MemMapStream::unmap(void* base, size_t size)
  294. {
  295. assert(0 != base && MAP_FAILED != base);
  296. assert(size % m_page_size == 0);
  297. ::munmap(base, size);
  298. }
  299. void MemMapStream::open(stream_position_t new_file_size, const std::string& fpath, int mode)
  300. {
  301.     using namespace std;
  302. mode |= O_LARGEFILE;
  303. init(new_file_size, fpath, mode);
  304.     if (is_open())
  305.         throw IOException("file already open");
  306.     m_hFile = ::open(fpath.c_str(), mode, S_IRWXU);
  307.     if (-1 == m_hFile)
  308.         cleanup_and_throw("failed opening file");
  309. assert(-1 != m_hFile);
  310.     if (m_mode & O_TRUNC)
  311. set_fsize(new_file_size);
  312. m_file_size = get_fsize();
  313. return;
  314. }
  315. stream_position_t MemMapStream::get_fsize()
  316. {
  317.     struct stat info;
  318.     bool success = ::fstat(m_hFile, &info) != -1;
  319.     if (success)
  320. return info.st_size;
  321. else
  322.         cleanup_and_throw("failed getting file size");
  323. }
  324. void MemMapStream::set_fsize(stream_position_t fsize)
  325. {
  326. if (ftruncate(m_hFile, fsize) == -1)
  327. {
  328. std::ostringstream oss;
  329. oss << "failed ftruncate(" << fsize << "), old_fsize=" << m_file_size;
  330.         cleanup_and_throw(oss.str().c_str());
  331. }
  332. m_file_size = fsize;
  333. }
  334. bool MemMapStream::remap_impl(stream_position_t fpos, size_t map_size)
  335. {
  336. if (m_beg)
  337. {
  338. if (0 != munmap(m_beg, align_up(m_end-m_beg, m_page_size)))
  339. cleanup_and_throw("failed unmapping in MemMapStream::remap_impl");
  340. }
  341. if (m_mode & O_RDWR && m_file_size < fpos + map_size)
  342. {
  343. set_fsize(fpos + map_size);
  344. }
  345. // int flags = m_mode & O_RDWR ? MAP_SHARED : MAP_PRIVATE;
  346. int flags = MAP_SHARED;
  347.     m_beg = (unsigned char*)::mmap(NULL, map_size,
  348.                          m_mode & O_RDWR ? (PROT_READ | PROT_WRITE) : PROT_READ,
  349.                          flags,
  350.                          m_hFile, fpos);
  351.     return (m_beg != MAP_FAILED);
  352. }
  353. bool MemMapStream::is_open() const throw()
  354. {
  355. return -1 != m_hFile;
  356. }
  357. #endif
  358. /**
  359.  @brief 
  360.   
  361.  @note:
  362.   - aligned_fpos must align at m_AllocationGranularity
  363.   - unaligned_size 可以不按 m_page_size 对齐
  364.  */
  365. bool MemMapStream::try_remap(stream_position_t aligned_fpos, size_t unaligned_size)
  366. {
  367. using namespace std;
  368. assert(aligned_fpos % m_AllocationGranularity == 0);
  369. if (aligned_fpos % m_AllocationGranularity != 0)
  370. throw IOException("can not map file offset not aligned at page size");
  371. if (!(m_mode & O_RDWR)) // read only
  372. {
  373. if (m_file_size <= aligned_fpos)
  374. {
  375. std::ostringstream oss;
  376. oss << "map readonly file out of region, at" << BOOST_CURRENT_FUNCTION
  377. ;
  378. throw EndOfFileException(oss.str().c_str());
  379. }
  380. else if (aligned_fpos + unaligned_size > m_file_size)
  381. {
  382. unaligned_size = size_t(m_file_size - aligned_fpos);
  383. }
  384. }
  385. size_t aligned_size = align_up(unaligned_size, m_page_size);
  386. bool bRet = remap_impl(aligned_fpos, aligned_size);
  387. if (bRet) {
  388. m_file_pos = aligned_fpos;
  389. m_pos = m_beg;
  390. m_end = m_beg + min(aligned_size, size_t(m_file_size - aligned_fpos));
  391. } else {
  392. m_beg = m_pos = m_end = NULL;
  393. }
  394. return bRet;
  395. }
  396. void MemMapStream::remap(stream_position_t aligned_fpos, size_t unaligned_size)
  397. {
  398. if (!try_remap(aligned_fpos, unaligned_size))
  399. {
  400. cleanup_and_throw("failed mapping view");
  401. }
  402. }
  403. void MemMapStream::unaligned_remap(stream_position_t fpos, size_t size)
  404. {
  405. using namespace std; // for max
  406. stream_position_t aligned_fpos = align_down(fpos, m_AllocationGranularity);
  407. size_t page_offset = size_t(fpos - aligned_fpos);
  408. size_t map_size = max(m_best_block_size, page_offset + size);
  409. if (!(m_mode & O_RDWR))
  410. { // mapped area can not beyond file size
  411. stream_position_t remain = m_file_size - this->tell();
  412. if (map_size > remain)
  413. map_size = size_t(remain);
  414. }
  415. remap(aligned_fpos, map_size);
  416. assert(m_pos == m_beg);
  417. m_pos = m_beg + page_offset;
  418. }
  419. void MemMapStream::cleanup_and_throw(const char* msg)
  420. {
  421. #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
  422. if (m_hMap != NULL)
  423.         ::CloseHandle(m_hMap);
  424.     if (m_hFile != INVALID_HANDLE_VALUE)
  425.         ::CloseHandle(m_hFile);
  426. #else
  427.     if (-1 != m_hFile)
  428.         ::close(m_hFile);
  429. #endif
  430. init();
  431. throw IOException(error_info(m_fpath, msg).c_str());
  432. }
  433. void MemMapStream::close()
  434. {
  435.     bool error = false;
  436. #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
  437. if (m_beg)
  438. error = !::UnmapViewOfFile(m_beg) || error;
  439. if (m_hMap != NULL)
  440. error = !::CloseHandle(m_hMap) || error;
  441. if (m_hFile != INVALID_HANDLE_VALUE)
  442.     error = !::CloseHandle(m_hFile) || error;
  443. #else
  444. if (m_beg)
  445. error = ::munmap(m_beg, align_up(m_end-m_beg, m_page_size)) != 0 || error;
  446. if (-1 != m_hFile)
  447. error = ::close(m_hFile) != 0 || error;
  448. #endif
  449. init();
  450.     if (error)
  451. {
  452. std::ostringstream oss;
  453. oss << "file="" << m_fpath << """ << ", error closing mapped file";
  454.         throw IOException(oss.str().c_str());
  455. }
  456. }
  457. void MemMapStream::flush()
  458. {
  459. // do nothing...?
  460. #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
  461. ::FlushFileBuffers(m_hFile);
  462. #else
  463. #endif
  464. }
  465. void MemMapStream::remap_and_skip(size_t size)
  466. {
  467. using namespace std;
  468. assert(m_end-m_pos < ptrdiff_t(size));
  469. size_t curr = m_end-m_pos;
  470. while (curr != size)
  471. {
  472. unaligned_remap(m_file_pos + (m_end-m_beg), m_best_block_size);
  473. size_t nbytes = min(size_t(size-curr), size_t(m_end-m_pos));
  474. m_pos += nbytes;
  475. curr += nbytes;
  476. }
  477. }
  478. void MemMapStream::remap_and_probe(size_t size)
  479. {
  480. using namespace std;
  481. // 如果 size 跨越了当前 map 的区域,
  482. // 就必须将当前 map 区域的最后部分也包括在 remap 区域中
  483. // 所以是 (m_pos-m_beg), 而非 (m_end-m_beg)
  484. stream_position_t old_pos = tell();
  485. unaligned_remap(m_file_pos + (m_pos-m_beg), max(m_best_block_size, size));
  486. m_pos = m_beg + (old_pos - m_file_pos);
  487. }
  488. size_t MemMapStream::remap_and_read(void* vbuf, size_t size)
  489. {
  490. using namespace std;
  491. assert(m_end-m_pos < ptrdiff_t(size));
  492. unsigned char* bbuf = (unsigned char*)vbuf;
  493. size_t curr = m_end-m_pos;
  494. memcpy(bbuf, m_pos, curr);
  495. while (curr != size)
  496. {
  497. stream_position_t fpos = m_file_pos + (m_end-m_beg);
  498. if (fpos > m_file_size)
  499. {
  500. std::ostringstream oss;
  501. oss << "this[fpos=" << m_file_pos
  502. << ", map_size=" << (m_end-m_beg)
  503. << ", fsize=" << m_file_size
  504. << "], at: " << BOOST_CURRENT_FUNCTION
  505. ;
  506. throw EndOfFileException(oss.str().c_str());
  507. }
  508. unaligned_remap(fpos, m_best_block_size);
  509. size_t nbytes = min(size_t(size-curr), size_t(m_end-m_pos));
  510. memcpy(bbuf+curr, m_pos, nbytes);
  511. m_pos += nbytes;
  512. curr += nbytes;
  513. }
  514. return curr;
  515. }
  516. size_t MemMapStream::remap_and_write(const void* vbuf, size_t size)
  517. {
  518. using namespace std;
  519. assert(m_end-m_pos < ptrdiff_t(size));
  520. const unsigned char* bbuf = (const unsigned char*)vbuf;
  521. size_t curr = m_end-m_pos;
  522. memcpy(m_pos, bbuf, curr);
  523. while (curr != size)
  524. {
  525. unaligned_remap(m_file_pos + (m_pos-m_beg), m_best_block_size);
  526. size_t nbytes = min(size_t(size-curr), size_t(m_end-m_pos));
  527. memcpy(m_pos, bbuf+curr, nbytes);
  528. m_pos += nbytes;
  529. curr += nbytes;
  530. }
  531. return curr;
  532. }
  533. void MemMapStream::remap_and_ensureRead(void* buf, size_t size)
  534. {
  535. size_t n = remap_and_read(buf, size);
  536. if (n != size)
  537. {
  538. std::ostringstream oss;
  539. oss << BOOST_CURRENT_FUNCTION;
  540. throw IOException(oss.str().c_str());
  541. }
  542. }
  543. void MemMapStream::remap_and_ensureWrite(const void* buf, size_t size)
  544. {
  545. size_t n = remap_and_write(buf, size);
  546. if (n != size)
  547. {
  548. std::ostringstream oss;
  549. oss << BOOST_CURRENT_FUNCTION;
  550. throw IOException(oss.str().c_str());
  551. }
  552. }
  553. unsigned char MemMapStream::remap_and_readByte()
  554. {
  555. unsigned char b;
  556. remap_and_ensureRead(&b, 1);
  557. return b;
  558. }
  559. int MemMapStream::remap_and_getByte()
  560. {
  561. try {
  562. return remap_and_readByte();
  563. } catch (const std::exception&) {
  564. return -1;
  565. }
  566. }
  567. void MemMapStream::remap_and_writeByte(unsigned char b)
  568. {
  569. remap_and_ensureWrite(&b, 1);
  570. }
  571. void MemMapStream::seek(stream_offset_t offset, int origin)
  572. {
  573. switch (origin)
  574. {
  575. default:
  576. throw std::invalid_argument(BOOST_CURRENT_FUNCTION);
  577. break;
  578. case 0:
  579. seek(offset);
  580. break;
  581. case 1:
  582. seek(tell() + offset);
  583. break;
  584. case 2:
  585. seek(size() + offset);
  586. break;
  587. }
  588. }
  589. void MemMapStream::seek(stream_position_t fpos)
  590. {
  591. stream_position_t fpos_end = m_file_pos + (m_end - m_beg);
  592. if (m_file_pos <= fpos && fpos <= fpos_end)
  593. {
  594. m_pos = m_beg + (fpos - m_file_pos);
  595. }
  596. else // seek out of region
  597. {
  598. stream_position_t new_fpos_beg = align_down(fpos, m_best_block_size);
  599. stream_position_t new_fpos_end = align_up  (fpos, m_best_block_size);
  600. if (!(m_mode & O_RDWR) && fpos > m_file_size)
  601. {
  602. std::ostringstream oss;
  603. oss << "out of file region, fpos[cur=" << m_file_pos
  604. << ", new=" << fpos
  605. << "], eofpos[cur=" << fpos_end << ", new=" << new_fpos_end
  606. << "], at: " << BOOST_CURRENT_FUNCTION;
  607. throw IOException(oss.str().c_str());
  608. }
  609. remap(new_fpos_beg, m_best_block_size);
  610. m_pos = m_beg + (fpos - new_fpos_beg);
  611. }
  612. }
  613. stream_position_t MemMapStream::size() const throw()
  614. {
  615. return m_file_size;
  616. }
  617. int MemMapStream::BinCompare(MemMapStream& y)
  618. {
  619. if (0 == m_file_size && 0 == y.m_file_size)
  620. return 0;
  621. if (m_best_block_size == y.m_best_block_size && m_file_size == y.m_file_size)
  622. {
  623. stream_position_t pos = 0;
  624. for (; pos + m_best_block_size <= m_file_size; pos += m_best_block_size)
  625. {
  626. MMS_MapRegion rx(*this, pos, m_best_block_size, O_RDONLY);
  627. MMS_MapRegion ry(y,     pos, m_best_block_size, O_RDONLY);
  628. int ret = ::memcmp(rx.base(), ry.base(), m_best_block_size);
  629. if (0 != ret) return ret;
  630. }
  631. if (pos == m_file_size)
  632. return 0;
  633. size_t n = m_file_size - pos;
  634. MMS_MapRegion rx(*this, pos, n, O_RDONLY);
  635. MMS_MapRegion ry(y,     pos, n, O_RDONLY);
  636. int ret = ::memcmp(rx.base(), ry.base(), n);
  637. return ret;
  638. }
  639. else
  640. {
  641. this->seek(0);
  642. y.seek(0);
  643. using namespace std;
  644. unsigned char bx, by;
  645. stream_position_t n = min(m_file_size, y.m_file_size);
  646. assert(n > 0);
  647. while (n--)
  648. {
  649. bx = readByte(), by = y.readByte();
  650. if (bx != by)
  651. return bx - by;
  652. }
  653. return m_file_size < y.m_file_size ? -1 :
  654. m_file_size > y.m_file_size ? +1 : 0;
  655. }
  656. assert(0); // would not go here
  657. }
  658. //////////////////////////////////////////////////////////////////////////
  659. // std::string MemMapStream::errmsg() const throw()
  660. // {
  661. //  IOException excep(m_errno, "MemMapStream");
  662. //  return excep.what();
  663. // }
  664. } // namespace febird