Commit f5e5d1bc authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent ade0ae79
...@@ -511,131 +511,6 @@ error _FileH::close() { ...@@ -511,131 +511,6 @@ error _FileH::close() {
return E(fileh._headf->close()); return E(fileh._headf->close());
} }
// mmap creates file mapping representing file[blk_start +blk_len) data as of wconn.at database state.
//
// If vma != nil, created mapping is associated with that vma of user-space virtual memory manager:
// virtmem calls FileH::mmap under virtmem lock when virtmem fileh is mmapped into vma.
pair<Mapping, error> _FileH::mmap(int64_t blk_start, int64_t blk_len, VMA *vma) {
_FileH& f = *this;
xerr::Contextf E("%s: mmap f<%s> [blk%ld +blk%ld)", v(f.wconn), v(f.foid), blk_start, blk_len);
error err;
if (blk_start < 0)
panic("blk_start < 0");
if (blk_len < 0)
panic("blk_len < 0");
int64_t blk_stop; // = blk_start + blk_len
if (__builtin_add_overflow(blk_start, blk_len, &blk_stop))
panic("blk_start + blk_len overflow int64");
int64_t stop;// = blk_stop *f.blksize;
if (__builtin_mul_overflow(blk_stop, f.blksize, &stop))
panic("(blk_start + blk_len)*f.blksize overflow int64");
int64_t start = blk_start*f.blksize;
// NOTE virtmem lock is held by virtmem caller
// XXX locking
// XXX + wconn.atMu.RLock() ? -> y (e.g. f.headfsize is used)
// f.mu.lock()
// create memory with head/f mapping and applied pins
// mmap-in zeros after f.size (else access to memory after file.size will raise SIGBUS)
uint8_t *mem_start, *mem_stop;
tie(mem_start, err) = mmap_ro(f._headf, start, blk_len*f.blksize);
if (err != nil)
return make_pair(nil, E(err));
mem_stop = mem_start + blk_len*f.blksize;
bool retok = false;
defer([&]() {
if (!retok)
mm::unmap(mem_start, mem_stop - mem_start); // ignore error
});
if (stop > f._headfsize) {
uint8_t *zmem_start = mem_start + (max(f._headfsize/*XXX -1 ?*/, start) - start);
err = mmap_zero_into_ro(zmem_start, mem_stop - zmem_start);
if (err != nil)
return make_pair(nil, E(err));
}
Mapping mmap = adoptref(new _Mapping());
mmap->fileh = newref(&f);
mmap->blk_start = blk_start;
mmap->mem_start = mem_start;
mmap->mem_stop = mem_stop;
mmap->vma = vma;
for (auto _ : f._pinned) { // TODO keep f._pinned ↑blk and use binary search
int64_t blk = _.first;
zodb::Tid rev = _.second;
if (!(blk_start <= blk && blk < blk_stop))
continue; // blk ∉ this mapping
err = mmap->_remmapblk(blk, rev);
if (err != nil)
return make_pair(nil, E(err));
}
if (vma != nil) {
if (vma->mmap_overlay_server != nil)
panic("vma is already associated with overlay server");
if (!(vma->addr_start == 0 && vma->addr_stop == 0))
panic("vma already covers !nil virtual memory area");
mmap->incref(); // vma->mmap_overlay_server is keeping ref to mmap
vma->mmap_overlay_server = mmap._ptr();
vma->addr_start = (uintptr_t)mmap->mem_start;
vma->addr_stop = (uintptr_t)mmap->mem_stop;
mmap->_assertVMAOk(); // just in case
}
f._mmaps.push_back(mmap); // TODO keep f._mmaps ↑blk_start
retok = true;
return make_pair(mmap, nil);
}
// unmap releases mapping memory from address space.
//
// After call to unmap the mapping must no longer be used.
// The association in between mapping and linked virtmem VMA is reset.
//
// Virtmem calls Mapping.unmap under virtmem lock when VMA is unmapped.
error _Mapping::unmap() {
Mapping mmap = newref(this); // XXX newref for std::remove
FileH f = mmap->fileh;
xerr::Contextf E("%s: f<%s>: unmap", v(f->wconn), v(f->foid));
// NOTE virtmem lock is held by virtmem caller
// XXX locking
// wconn.atMu.RLock() + f.mu.lock()
if (mmap->vma != nil) {
mmap->_assertVMAOk();
VMA *vma = mmap->vma;
vma->mmap_overlay_server = nil;
mmap->decref(); // vma->mmap_overlay_server was holding a ref to mmap
vma->addr_start = 0;
vma->addr_stop = 0;
mmap->vma = nil;
}
error err = mm::unmap(mmap->mem_start, mmap->mem_stop - mmap->mem_start);
mmap->mem_start = nil;
mmap->mem_stop = nil;
// XXX clear other fields?
// XXX do it first? (to avoid pinner going through f.mmaps and hitting unmapped memory)
//f->_mmaps.remove(mmap);
f->_mmaps.erase(
std::remove(f->_mmaps.begin(), f->_mmaps.end(), mmap),
f->_mmaps.end());
return E(err);
}
// resync resyncs connection and its file mappings onto different database view. // resync resyncs connection and its file mappings onto different database view.
// XXX place=? -> closer to pinner & connect // XXX place=? -> closer to pinner & connect
error _Conn::resync(zodb::Tid at) { error _Conn::resync(zodb::Tid at) {
...@@ -770,6 +645,130 @@ error _Conn::resync(zodb::Tid at) { ...@@ -770,6 +645,130 @@ error _Conn::resync(zodb::Tid at) {
return nil; return nil;
} }
// mmap creates file mapping representing file[blk_start +blk_len) data as of wconn.at database state.
//
// If vma != nil, created mapping is associated with that vma of user-space virtual memory manager:
// virtmem calls FileH::mmap under virtmem lock when virtmem fileh is mmapped into vma.
pair<Mapping, error> _FileH::mmap(int64_t blk_start, int64_t blk_len, VMA *vma) {
_FileH& f = *this;
xerr::Contextf E("%s: mmap f<%s> [blk%ld +blk%ld)", v(f.wconn), v(f.foid), blk_start, blk_len);
error err;
if (blk_start < 0)
panic("blk_start < 0");
if (blk_len < 0)
panic("blk_len < 0");
int64_t blk_stop; // = blk_start + blk_len
if (__builtin_add_overflow(blk_start, blk_len, &blk_stop))
panic("blk_start + blk_len overflow int64");
int64_t stop;// = blk_stop *f.blksize;
if (__builtin_mul_overflow(blk_stop, f.blksize, &stop))
panic("(blk_start + blk_len)*f.blksize overflow int64");
int64_t start = blk_start*f.blksize;
// NOTE virtmem lock is held by virtmem caller
// XXX locking
// XXX + wconn.atMu.RLock() ? -> y (e.g. f.headfsize is used)
// f.mu.lock()
// create memory with head/f mapping and applied pins
// mmap-in zeros after f.size (else access to memory after file.size will raise SIGBUS)
uint8_t *mem_start, *mem_stop;
tie(mem_start, err) = mmap_ro(f._headf, start, blk_len*f.blksize);
if (err != nil)
return make_pair(nil, E(err));
mem_stop = mem_start + blk_len*f.blksize;
bool retok = false;
defer([&]() {
if (!retok)
mm::unmap(mem_start, mem_stop - mem_start); // ignore error
});
if (stop > f._headfsize) {
uint8_t *zmem_start = mem_start + (max(f._headfsize/*XXX -1 ?*/, start) - start);
err = mmap_zero_into_ro(zmem_start, mem_stop - zmem_start);
if (err != nil)
return make_pair(nil, E(err));
}
Mapping mmap = adoptref(new _Mapping());
mmap->fileh = newref(&f);
mmap->blk_start = blk_start;
mmap->mem_start = mem_start;
mmap->mem_stop = mem_stop;
mmap->vma = vma;
for (auto _ : f._pinned) { // TODO keep f._pinned ↑blk and use binary search
int64_t blk = _.first;
zodb::Tid rev = _.second;
if (!(blk_start <= blk && blk < blk_stop))
continue; // blk ∉ this mapping
err = mmap->_remmapblk(blk, rev);
if (err != nil)
return make_pair(nil, E(err));
}
if (vma != nil) {
if (vma->mmap_overlay_server != nil)
panic("vma is already associated with overlay server");
if (!(vma->addr_start == 0 && vma->addr_stop == 0))
panic("vma already covers !nil virtual memory area");
mmap->incref(); // vma->mmap_overlay_server is keeping ref to mmap
vma->mmap_overlay_server = mmap._ptr();
vma->addr_start = (uintptr_t)mmap->mem_start;
vma->addr_stop = (uintptr_t)mmap->mem_stop;
mmap->_assertVMAOk(); // just in case
}
f._mmaps.push_back(mmap); // TODO keep f._mmaps ↑blk_start
retok = true;
return make_pair(mmap, nil);
}
// unmap releases mapping memory from address space.
//
// After call to unmap the mapping must no longer be used.
// The association in between mapping and linked virtmem VMA is reset.
//
// Virtmem calls Mapping.unmap under virtmem lock when VMA is unmapped.
error _Mapping::unmap() {
Mapping mmap = newref(this); // XXX newref for std::remove
FileH f = mmap->fileh;
xerr::Contextf E("%s: f<%s>: unmap", v(f->wconn), v(f->foid));
// NOTE virtmem lock is held by virtmem caller
// XXX locking
// wconn.atMu.RLock() + f.mu.lock()
if (mmap->vma != nil) {
mmap->_assertVMAOk();
VMA *vma = mmap->vma;
vma->mmap_overlay_server = nil;
mmap->decref(); // vma->mmap_overlay_server was holding a ref to mmap
vma->addr_start = 0;
vma->addr_stop = 0;
mmap->vma = nil;
}
error err = mm::unmap(mmap->mem_start, mmap->mem_stop - mmap->mem_start);
mmap->mem_start = nil;
mmap->mem_stop = nil;
// XXX clear other fields?
// XXX do it first? (to avoid pinner going through f.mmaps and hitting unmapped memory)
//f->_mmaps.remove(mmap);
f->_mmaps.erase(
std::remove(f->_mmaps.begin(), f->_mmaps.end(), mmap),
f->_mmaps.end());
return E(err);
}
// _remmapblk remmaps mapping memory for file[blk] to be viewing database as of @at state. // _remmapblk remmaps mapping memory for file[blk] to be viewing database as of @at state.
// //
// at=TidHead means unpin to head/ . // at=TidHead means unpin to head/ .
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment