Steven Siloti
2016-11-03 03:20:43 UTC
I've been working on figuring out how to integrate mmapped file I/O with
libtorrent and before I go further I want to make sure this fits with
arvid's plans for this feature.
The idea is to wrap the file class with a pool_file class which handles the
details of managing the mappings and performing I/O using them. Instances
of pool_file are tied to an instance of file_pool because the two need to
interact to perform lru eviction of mappings on 32-bit systems. A wrapper
class is also needed because if the file class held strong references to
the mappings it would create a reference cycle.
On 64-bit systems things are relatively simple. We lazily map the entire
file and create a new mapping any time the size of the file is changed.
Even with 64-bit we need to reference count the mappings so that extending
the file size doesn't disturb concurrent I/O.
There is a potential performance gotcha in that munmap() is O(n) with
respect to the number of faulted in pages being unmapped. We therefor need
to try to avoid the case of a file being repeatedly extended by small
amounts. With full allocation this obviously isn't a problem.
On 32-bit systems mappings are created on-demand and cached up to some
maximum total mapped size. The size of each mapping is capped at some
arbitrary value, say 16MB. When a new mapping is requested the lru mappings
will be evicted until there is enough free space to create the new mapping.
There's a lot of complexity here which I haven't fully worked out yet.
Currently I only have 64-bit POSIX support codded up and passing the unit
tests. You can find it here:
https://github.com/ssiloti/libtorrent/commit/1dd5b130c2c4859dc1f895272cd3cc
e7e5939fd4
It still needs a lot of polish obviously, so excuse any oddities in the
details.
libtorrent and before I go further I want to make sure this fits with
arvid's plans for this feature.
The idea is to wrap the file class with a pool_file class which handles the
details of managing the mappings and performing I/O using them. Instances
of pool_file are tied to an instance of file_pool because the two need to
interact to perform lru eviction of mappings on 32-bit systems. A wrapper
class is also needed because if the file class held strong references to
the mappings it would create a reference cycle.
On 64-bit systems things are relatively simple. We lazily map the entire
file and create a new mapping any time the size of the file is changed.
Even with 64-bit we need to reference count the mappings so that extending
the file size doesn't disturb concurrent I/O.
There is a potential performance gotcha in that munmap() is O(n) with
respect to the number of faulted in pages being unmapped. We therefor need
to try to avoid the case of a file being repeatedly extended by small
amounts. With full allocation this obviously isn't a problem.
On 32-bit systems mappings are created on-demand and cached up to some
maximum total mapped size. The size of each mapping is capped at some
arbitrary value, say 16MB. When a new mapping is requested the lru mappings
will be evicted until there is enough free space to create the new mapping.
There's a lot of complexity here which I haven't fully worked out yet.
Currently I only have 64-bit POSIX support codded up and passing the unit
tests. You can find it here:
https://github.com/ssiloti/libtorrent/commit/1dd5b130c2c4859dc1f895272cd3cc
e7e5939fd4
It still needs a lot of polish obviously, so excuse any oddities in the
details.