ReadableStore* ReadableStore::openStore(PathRef segDir, fstring fname) { size_t sufpos = fname.size(); while (sufpos > 0 && fname[sufpos-1] != '.') --sufpos; auto suffix = fname.substr(sufpos); size_t idx = s_storeFactory.find_i(suffix); if (idx < s_storeFactory.end_i()) { const auto& factory = s_storeFactory.val(idx); ReadableStore* store = factory(); assert(NULL != store); if (NULL == store) { THROW_STD(runtime_error, "store factory should not return NULL store"); } auto fpath = segDir / fname.str(); store->load(fpath); return store; } else { THROW_STD(invalid_argument , "store type '%.*s' of '%s' is not registered" , suffix.ilen(), suffix.data() , (segDir / fname.str()).string().c_str() ); return NULL; // avoid compiler warning } }
TERARK_DLL_EXPORT void truncate_file(const char* fpath, unsigned long long size) { #ifdef _MSC_VER Auto_close_fd fd(::_open(fpath, O_CREAT|O_BINARY|O_RDWR, 0644)); #else Auto_close_fd fd(::open(fpath, O_CREAT|O_RDWR, 0644)); #endif if (fd < 0) { THROW_STD(logic_error , "FATAL: ::open(%s, O_CREAT|O_BINARY|O_RDWR) = %s" , fpath, strerror(errno)); } #ifdef _MSC_VER int err = ::_chsize_s(fd, size); if (err) { THROW_STD(logic_error, "FATAL: ::_chsize_s(%s, %lld) = %s" , fpath, size, strerror(errno)); } #else int err = ::ftruncate(fd, size); if (err) { THROW_STD(logic_error, "FATAL: ::truncate(%s, %lld) = %s" , fpath, size, strerror(errno)); } #endif }
bool indexInsert(size_t indexId, fstring key, llong recId) override { assert(started == m_status); assert(indexId < m_indices.size()); WT_ITEM item; WT_SESSION* ses = m_session.ses; const Schema& schema = m_sconf.getIndexSchema(indexId); WT_CURSOR* cur = m_indices[indexId].insert; WtWritableIndex::setKeyVal(schema, cur, key, recId, &item, &m_wrtBuf); int err = cur->insert(cur); m_sizeDiff += sizeof(llong) + key.size(); if (schema.m_isUnique) { if (WT_DUPLICATE_KEY == err) { return false; } if (err) { THROW_STD(invalid_argument , "ERROR: wiredtiger insert unique index: %s", ses->strerror(ses, err)); } } else { if (WT_DUPLICATE_KEY == err) { assert(0); // assert in debug return true; // ignore in release } if (err) { THROW_STD(invalid_argument , "ERROR: wiredtiger insert multi index: %s", ses->strerror(ses, err)); } } return true; }
bool LineBuf::read_binary_tuple(int32_t* offsets, size_t arity, FILE* f) { assert(NULL != offsets); offsets[0] = 0; size_t n_read = fread(offsets+1, 1, sizeof(int32_t) * arity, f); if (n_read != sizeof(int32_t) * arity) { return false; } for (size_t i = 0; i < arity; ++i) { assert(offsets[i+1] >= 0); offsets[i+1] += offsets[i]; } size_t len = offsets[arity]; if (this->capacity < len) { char* q = (char*)realloc(this->p, len); if (NULL == q) { THROW_STD(invalid_argument , "Out of memory when reading record[size=%zd(0x%zX)]" , len, len ); } this->p = q; this->capacity = len; } n_read = fread(this->p, 1, len, f); if (n_read != len) { THROW_STD(invalid_argument , "fread record data failed: request=%zd, readed=%zd\n" , len, n_read ); } this->n = len; return true; // len can be 0 }
void StrBuilder::setEof(int end_offset) { assert(end_offset < 0); assert(NULL != memFile); int rv = fflush(memFile); if (rv != 0) { THROW_STD(runtime_error, "fflush on memstream"); } s[n+end_offset] = '\0'; rv = fseek(memFile, end_offset, SEEK_END); if (rv != 0) { THROW_STD(runtime_error, "fseek on memstream"); } assert(NULL != s); assert((long)n + end_offset >= 0); }
void MockReadonlyStore::build(const Schema& schema, SortableStrVec& data) { size_t fixlen = schema.getFixedRowLen(); if (0 == fixlen) { if (data.str_size() >= UINT32_MAX) { THROW_STD(length_error, "keys.str_size=%lld is too large", llong(data.str_size())); } // reuse memory of keys.m_index auto offsets = (uint32_t*)data.m_index.data(); size_t rows = data.m_index.size(); for (size_t i = 0; i < rows; ++i) { uint32_t offset = uint32_t(data.m_index[i].offset); offsets[i] = offset; } offsets[rows] = data.str_size(); BOOST_STATIC_ASSERT(sizeof(SortableStrVec::SEntry) == 4*3); m_rows.offsets.risk_set_data(offsets); m_rows.offsets.risk_set_size(rows + 1); m_rows.offsets.risk_set_capacity(3 * rows); m_rows.offsets.shrink_to_fit(); data.m_index.risk_release_ownership(); #if !defined(NDEBUG) assert(data.m_strpool.size() == m_rows.offsets.back()); for (size_t i = 0; i < rows; ++i) { assert(m_rows.offsets[i] < m_rows.offsets[i+1]); } #endif } m_rows.strpool.swap((valvec<char>&)data.m_strpool); m_fixedLen = fixlen; }
void ZipIntKeyIndex::getValueAppend(llong id, valvec<byte>* val, DbContext*) const { assert(id >= 0); size_t idx = size_t(id); assert(idx < m_keys.size()); switch (m_keyType) { default: THROW_STD(invalid_argument, "Bad m_keyType=%s", Schema::columnTypeStr(m_keyType)); case ColumnType::Sint08: keyAppend< int8_t >(idx, val); break; case ColumnType::Uint08: keyAppend<uint8_t >(idx, val); break; case ColumnType::Sint16: keyAppend< int16_t>(idx, val); break; case ColumnType::Uint16: keyAppend<uint16_t>(idx, val); break; case ColumnType::Sint32: keyAppend< int32_t>(idx, val); break; case ColumnType::Uint32: keyAppend<uint32_t>(idx, val); break; case ColumnType::Sint64: keyAppend< int64_t>(idx, val); break; case ColumnType::Uint64: keyAppend<uint64_t>(idx, val); break; case ColumnType::VarSint: { byte buf[16]; byte* end = save_var_int64(buf, int64_t(m_minKey + m_keys.get(idx))); val->append(buf, end - buf); break; } case ColumnType::VarUint: { byte buf[16]; byte* end = save_var_uint64(buf, uint64_t(m_minKey + m_keys.get(idx))); val->append(buf, end - buf); break; } } }
int seekLowerBound(fstring key, llong* id, valvec<byte>* retKey) override { assert(key.size() == sizeof(Int)); if (key.size() != sizeof(Int)) { THROW_STD(invalid_argument, "key.size must be sizeof(Int)=%d", int(sizeof(Int))); } auto owner = static_cast<const SeqNumIndex*>(m_index.get()); Int keyId = unaligned_load<Int>(key.udata()); if (keyId <= owner->m_min) { m_curr = 0; return -1; } else if (keyId > owner->m_min + owner->m_cnt) { m_curr = owner->m_cnt; *id = owner->m_cnt - 1; Int forwardMax = owner->m_min + owner->m_cnt - 1; retKey->assign((const byte*)&forwardMax, sizeof(Int)); return 1; } else { keyId -= owner->m_min; m_curr = keyId; *id = keyId; retKey->assign(key.udata(), key.size()); return 0; } }
explicit WtDbTransaction(WtWritableSegment* seg) : m_seg(seg), m_sconf(*seg->m_schema) { WT_CONNECTION* conn = seg->m_wtConn; int err = conn->open_session(conn, NULL, NULL, &m_session.ses); if (err) { THROW_STD(invalid_argument , "FATAL: wiredtiger open session(dir=%s) = %s" , conn->get_home(conn), wiredtiger_strerror(err) ); } WT_SESSION* ses = m_session.ses; err = ses->open_cursor(ses, g_dataStoreUri, NULL, "overwrite=true", &m_store.cursor); if (err) { THROW_STD(invalid_argument , "ERROR: wiredtiger store open cursor: %s" , ses->strerror(ses, err)); } m_indices.resize(seg->m_indices.size()); for (size_t indexId = 0; indexId < m_indices.size(); ++indexId) { ReadableIndex* index = seg->m_indices[indexId].get(); WtWritableIndex* wtIndex = dynamic_cast<WtWritableIndex*>(index); assert(NULL != wtIndex); const char* uri = wtIndex->getIndexUri().c_str(); err = ses->open_cursor(ses, uri, NULL, "overwrite=false", &m_indices[indexId].insert.cursor); if (err) { THROW_STD(invalid_argument , "ERROR: wiredtiger open index cursor: %s" , ses->strerror(ses, err)); } err = ses->open_cursor(ses, uri, NULL, "overwrite=true", &m_indices[indexId].overwrite.cursor); if (err) { THROW_STD(invalid_argument , "ERROR: wiredtiger open index cursor: %s" , ses->strerror(ses, err)); } } m_sizeDiff = 0; m_wrtStore = dynamic_cast<WtWritableStore*>(seg->m_wrtStore.get()); assert(nullptr != m_store); g_wtDbTxnLiveCnt++; g_wtDbTxnCreatedCnt++; if (getEnvBool("TerarkDB_TrackBuggyObjectLife")) { fprintf(stderr, "DEBUG: WtDbTransaction live count = %zd, created = %zd\n" , g_wtDbTxnLiveCnt.load(), g_wtDbTxnCreatedCnt.load()); } }
StrBuilder::StrBuilder() { s = NULL; n = 0; memFile = open_memstream(&s, &n); if (NULL == memFile) { THROW_STD(runtime_error, "open_memstream"); } }
ReadableStore::RegisterStoreFactory::RegisterStoreFactory (const char* fnameSuffix, const std::function<ReadableStore*()>& f) { auto ib = s_storeFactory.insert_i(fnameSuffix, f); assert(ib.second); if (!ib.second) THROW_STD(invalid_argument, "duplicate suffix: %s", fnameSuffix); }
bool SeqNumIndex<Int>::insert(fstring key, llong id, DbContext*) { assert(key.size() == sizeof(Int)); assert(id >= 0); if (key.size() != sizeof(Int)) { THROW_STD(invalid_argument, "key.size must be sizeof(Int)=%d", int(sizeof(Int))); } Int keyId = unaligned_load<Int>(key.udata()); if (keyId != m_min + id) { THROW_STD(invalid_argument, "key must be consistent with id in SeqNumIndex"); } if (llong(m_cnt) < id + 1) { m_cnt = id + 1; } return 1; }
StrBuilder& StrBuilder::flush() { assert(NULL != memFile); int rv = fflush(memFile); if (rv != 0) { THROW_STD(runtime_error, "fflush on memstream"); } // assert(NULL != s); return *this; }
const char* StrBuilder::c_str() { assert(NULL != memFile); int rv = fflush(memFile); if (rv != 0) { THROW_STD(runtime_error, "fflush on memstream"); } assert(NULL != s); return s; }
StrBuilder::operator std::string() const { assert(NULL != memFile); int rv = fflush(memFile); if (rv != 0) { THROW_STD(runtime_error, "fflush on memstream"); } assert(NULL != s); return std::string(s, n); }
void StrBuilder::setEof(int end_offset, const char* endmark) { assert(end_offset < 0); assert(NULL != endmark); assert(NULL != memFile); int rv = fseek(memFile, end_offset, SEEK_END); if (rv != 0) { THROW_STD(runtime_error, "fflush on memstream"); } rv = fputs(endmark, memFile); if (EOF == rv) { THROW_STD(runtime_error, "fputs(endmark, memFile)"); } rv = fflush(memFile); if (rv != 0) { THROW_STD(runtime_error, "fflush on memstream"); } assert(NULL != s); assert((long)n + end_offset >= 0); }
bool SeqNumIndex<Int>::replace(fstring key, llong id, llong newId, DbContext*) { assert(key.size() == sizeof(Int)); assert(id >= 0); assert(id == newId); if (key.size() != sizeof(Int)) { THROW_STD(invalid_argument, "key.size must be sizeof(Int)=%d", int(sizeof(Int))); } if (id != newId) { THROW_STD(invalid_argument, "replace with different id is not supported by SeqNumIndex"); } Int keyId = unaligned_load<Int>(key.udata()); if (keyId != m_min + newId) { THROW_STD(invalid_argument, "key must be consistent with id in SeqNumIndex"); } return 1; }
ptrdiff_t LineBuf::getline(FILE* f) { assert(NULL != f); #if defined(__USE_GNU) || defined(__CYGWIN__) || defined(__CYGWIN32__) // has ::getline return n = ::getline(&p, &capacity, f); #else // #error only _GNU_SOURCE is supported if (NULL == p) { capacity = BUFSIZ; p = (char*)malloc(BUFSIZ); if (NULL == p) THROW_STD(runtime_error, "malloc(BUFSIZ=%d) failed", BUFSIZ); } n = 0; p[0] = '\0'; for (;;) { assert(n < capacity); char* ret = ::fgets(p + n, capacity - n, f); size_t len = ::strlen(p + n); if (0 == len && (feof(f) || ferror(f))) return -1; n += len; if (ret) { if (capacity-1 == n && p[n-1] != '\n') { size_t newcap = capacity * 2; ret = (char*)realloc(p, newcap); if (NULL == ret) THROW_STD(runtime_error, "realloc(newcap=%zd)", newcap); p = ret; capacity = newcap; } else { return ptrdiff_t(n); } } else if (feof(f)) return ptrdiff_t(n); else return -1; } #endif }
void do_rollback() override { resetCursors(); #if TERARK_WT_USE_TXN WT_SESSION* ses = m_session.ses; int err = ses->rollback_transaction(ses, NULL); if (err) { THROW_STD(invalid_argument , "ERROR: wiredtiger rollback_transaction: %s" , ses->strerror(ses, err)); } #endif }
StrBuilder& StrBuilder::printf(const char* format, ...) { assert(NULL != format); assert(NULL != memFile); va_list ap; va_start(ap, format); int rv = vfprintf(memFile, format, ap); va_end(ap); if (rv < 0) { THROW_STD(runtime_error, "vfprintf on memstream"); } return *this; }
void MockReadonlyIndex::build(SortableStrVec& keys) { const Schema* schema = m_schema; const byte* base = keys.m_strpool.data(); size_t fixlen = schema->getFixedRowLen(); if (fixlen) { assert(keys.m_index.size() == 0); assert(keys.str_size() % fixlen == 0); m_ids.resize_no_init(keys.str_size() / fixlen); for (size_t i = 0; i < m_ids.size(); ++i) m_ids[i] = i; std::sort(m_ids.begin(), m_ids.end(), [=](size_t x, size_t y) { fstring xs(base + fixlen * x, fixlen); fstring ys(base + fixlen * y, fixlen); int r = schema->compareData(xs, ys); if (r) return r < 0; else return x < y; }); } else { if (keys.str_size() >= UINT32_MAX) { THROW_STD(length_error, "keys.str_size=%lld is too large", llong(keys.str_size())); } // reuse memory of keys.m_index auto offsets = (uint32_t*)keys.m_index.data(); size_t rows = keys.m_index.size(); m_ids.resize_no_init(rows); for (size_t i = 0; i < rows; ++i) m_ids[i] = i; for (size_t i = 0; i < rows; ++i) { uint32_t offset = uint32_t(keys.m_index[i].offset); offsets[i] = offset; } offsets[rows] = keys.str_size(); std::sort(m_ids.begin(), m_ids.end(), [=](size_t x, size_t y) { size_t xoff0 = offsets[x], xoff1 = offsets[x+1]; size_t yoff0 = offsets[y], yoff1 = offsets[y+1]; fstring xs(base + xoff0, xoff1 - xoff0); fstring ys(base + yoff0, yoff1 - yoff0); int r = schema->compareData(xs, ys); if (r) return r < 0; else return x < y; }); BOOST_STATIC_ASSERT(sizeof(SortableStrVec::SEntry) == 4*3); m_keys.offsets.risk_set_data(offsets); m_keys.offsets.risk_set_size(rows + 1); m_keys.offsets.risk_set_capacity(3 * rows); m_keys.offsets.shrink_to_fit(); keys.m_index.risk_release_ownership(); } m_keys.strpool.swap((valvec<char>&)keys.m_strpool); m_fixedLen = fixlen; }
bool seekExact(llong id, valvec<byte>* val) override { auto store = static_cast<WrStore*>(m_store.get()); SpinRwLock lock(store->m_rwMutex, false); if (id < 0 || id >= llong(store->m_rows.size())) { THROW_STD(out_of_range, "Invalid id = %lld, rows = %zd" , id, store->m_rows.size()); } if (!store->m_rows[id].empty()) { *val = store->m_rows[id]; m_id = id; return true; } return false; }
llong ZipIntKeyIndex::dataInflateSize() const { switch (m_keyType) { default: THROW_STD(invalid_argument, "Bad m_keyType=%s", Schema::columnTypeStr(m_keyType)); case ColumnType::Sint08: case ColumnType::Uint08: return 1 * m_keys.size(); case ColumnType::Sint16: case ColumnType::Uint16: return 2 * m_keys.size(); case ColumnType::Sint32: case ColumnType::Uint32: return 4 * m_keys.size(); case ColumnType::Sint64: case ColumnType::Uint64: return 8 * m_keys.size(); } }
// static void SchemaRecordCoder::parseToFields(const BSONObj& obj, FieldsMap* fields) { fields->erase_all(); // std::string fieldnames; BSONForEach(elem, obj) { // const char* fieldname = elem.fieldName(); // gcc-4.9.3 produce error code fstring fieldname = elem.fieldName(); // gcc is ok auto ib = fields->insert_i(fieldname); // LOG(1) << "insert('" << fieldname.c_str() << "', len=" << fieldname.size() << ")=" << ib.first; // LOG(1) << "find_i('" << fieldname.c_str() << "', len=" << fieldname.size() << ")=" << fields->find_i(fieldname); if (!ib.second) { THROW_STD(invalid_argument, "bad bson: duplicate fieldname: %s", fieldname.c_str()); } invariant(fields->elem_at(ib.first).size() == fieldname.size()); // fieldnames += fieldname.c_str(); // fieldnames.push_back(','); }
void do_startTransaction() override { #if TERARK_WT_USE_TXN WT_SESSION* ses = m_session.ses; const char* txnConfig = getenv("TerarkDB_WiredtigerTransactionConfig"); if (NULL == txnConfig) { // wiredtiger 2.8.0 is not binary compatible with 2.7.0 txnConfig = "isolation=read-committed,sync=false"; } // fprintf(stderr, "INFO: %s: txnConfig=%s\n", BOOST_CURRENT_FUNCTION, txnConfig); int err = ses->begin_transaction(ses, txnConfig); if (err) { THROW_STD(invalid_argument , "ERROR: wiredtiger begin_transaction: %s" , ses->strerror(ses, err)); } #endif m_sizeDiff = 0; }
std::pair<size_t, bool> ZipIntKeyIndex::searchLowerBound(fstring key) const { switch (m_keyType) { default: THROW_STD(invalid_argument, "Bad m_keyType=%s", Schema::columnTypeStr(m_keyType)); case ColumnType::Sint08 : return IntVecLowerBound< int8_t >(key); break; case ColumnType::Uint08 : return IntVecLowerBound<uint8_t >(key); break; case ColumnType::Sint16 : return IntVecLowerBound< int16_t>(key); break; case ColumnType::Uint16 : return IntVecLowerBound<uint16_t>(key); break; case ColumnType::Sint32 : return IntVecLowerBound< int32_t>(key); break; case ColumnType::Uint32 : return IntVecLowerBound<uint32_t>(key); break; case ColumnType::Sint64 : return IntVecLowerBound< int64_t>(key); break; case ColumnType::Uint64 : return IntVecLowerBound<uint64_t>(key); break; case ColumnType::VarSint: return IntVecLowerBound< int64_t>(key); break; case ColumnType::VarUint: return IntVecLowerBound<uint64_t>(key); break; } abort(); return {}; }
void indexSearch(size_t indexId, fstring key, valvec<llong>* recIdvec) override { assert(started == m_status); assert(indexId < m_indices.size()); WT_ITEM item; WT_SESSION* ses = m_session.ses; const Schema& schema = m_sconf.getIndexSchema(indexId); WT_CURSOR* cur = m_indices[indexId].insert; WtWritableIndex::setKeyVal(schema, cur, key, 0, &item, &m_wrtBuf); recIdvec->erase_all(); if (schema.m_isUnique) { int err = cur->search(cur); BOOST_SCOPE_EXIT(cur) { cur->reset(cur); } BOOST_SCOPE_EXIT_END; if (WT_NOTFOUND == err) { return; } if (err) { THROW_STD(invalid_argument , "ERROR: wiredtiger search: %s", ses->strerror(ses, err)); } llong recId = 0; cur->get_value(cur, &recId); recIdvec->push_back(recId); }
//! delete all object in list, and clear self void AccessByNameID<void*>::destroy() { std::vector<uintptr_t> used_id; m_byid.get_used_id(&used_id); std::vector<uintptr_t> bynamep(m_byname->size()); NameMapForAccessByNameID::iterator iter = m_byname->begin(); for (uintptr_t i = 0; iter != m_byname->end(); ++iter) bynamep[i++] = (uintptr_t)iter->second; for (uintptr_t i = 0; i != used_id.size(); ++i) used_id[i] = m_byid.get_val(used_id[i]); std::sort(used_id.begin(), used_id.end()); std::sort(bynamep.begin(), bynamep.end()); uintptr_t n = std::set_union(used_id.begin(), used_id.end(), bynamep.begin(), bynamep.end(), used_id.begin()) - used_id.begin(); assert(used_id.size() == n); if (used_id.size() != n) { THROW_STD(runtime_error, "(used_id.size=%zd) != (n=%zd)", used_id.size(), n); } for (uintptr_t i = 0; i != n; ++i) on_destroy((void*)used_id[i]); m_byid.clear(); m_byname->clear(); }
void EmptyIndexStore::getValueAppend(llong id, valvec<byte>* val, DbContext*) const { THROW_STD(invalid_argument, "Invalid method call"); }
void* mmap_load(const char* fname, size_t* fsize, bool writable, bool populate) { #ifdef _MSC_VER LARGE_INTEGER lsize; HANDLE hFile = CreateFileA(fname , GENERIC_READ |(writable ? GENERIC_WRITE : 0) , FILE_SHARE_DELETE | FILE_SHARE_READ | (writable ? FILE_SHARE_WRITE : 0) , NULL // lpSecurityAttributes , writable ? OPEN_ALWAYS : OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL // hTemplateFile ); if (INVALID_HANDLE_VALUE == hFile) { DWORD err = GetLastError(); THROW_STD(logic_error, "CreateFile(fname=%s).Err=%d(%X)" , fname, err, err); } if (writable) { // bool isNewFile = GetLastError() != ERROR_ALREADY_EXISTS; bool isNewFile = GetLastError() == 0; if (isNewFile) { SetFilePointer(hFile, 8*1024, NULL, SEEK_SET); SetEndOfFile(hFile); SetFilePointer(hFile, 0, NULL, SEEK_SET); } } if (!GetFileSizeEx(hFile, &lsize)) { DWORD err = GetLastError(); CloseHandle(hFile); THROW_STD(logic_error, "GetFileSizeEx(fname=%s).Err=%d(%X)" , fname, err, err); } if (lsize.QuadPart > size_t(-1)) { CloseHandle(hFile); THROW_STD(logic_error, "fname=%s fsize=%I64u(%I64X) too large" , fname, lsize.QuadPart, lsize.QuadPart); } *fsize = size_t(lsize.QuadPart); DWORD flProtect = writable ? PAGE_READWRITE : PAGE_READONLY; HANDLE hMmap = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL); if (NULL == hMmap) { DWORD err = GetLastError(); CloseHandle(hFile); THROW_STD(runtime_error, "CreateFileMapping(fname=%s).Err=%d(0x%X)" , fname, err, err); } DWORD desiredAccess = (writable ? FILE_MAP_WRITE : 0) | FILE_MAP_READ; void* base = MapViewOfFile(hMmap, desiredAccess, 0, 0, 0); if (NULL == base) { DWORD err = GetLastError(); ::CloseHandle(hMmap); ::CloseHandle(hFile); THROW_STD(runtime_error, "MapViewOfFile(fname=%s).Err=%d(0x%X)" , fname, err, err); } if (populate) { WIN32_MEMORY_RANGE_ENTRY vm; vm.VirtualAddress = base; vm.NumberOfBytes = *fsize; PrefetchVirtualMemory(GetCurrentProcess(), 1, &vm, 0); } ::CloseHandle(hMmap); // close before UnmapViewOfFile is OK ::CloseHandle(hFile); #else int openFlags = writable ? O_RDWR : O_RDONLY; int fd = ::open(fname, openFlags); if (fd < 0) { int err = errno; THROW_STD(logic_error, "open(fname=%s, %s) = %d(%X): %s" , fname, writable ? "O_RDWR" : "O_RDONLY" , err, err, strerror(err)); } struct stat st; if (::fstat(fd, &st) < 0) { THROW_STD(logic_error, "stat(fname=%s) = %s", fname, strerror(errno)); } *fsize = st.st_size; int flProtect = (writable ? PROT_WRITE : 0) | PROT_READ; int flags = MAP_SHARED | (populate ? MAP_POPULATE : 0); void* base = ::mmap(NULL, st.st_size, flProtect, flags, fd, 0); if (MAP_FAILED == base) { ::close(fd); THROW_STD(logic_error, "mmap(fname=%s, %s SHARED, size=%lld) = %s" , fname, writable ? "READWRITE" : "READ" , (long long)st.st_size, strerror(errno)); } ::close(fd); #endif return base; }