diff options
author | Christopher Haster <chaster@utexas.edu> | 2017-10-17 03:08:47 +0300 |
---|---|---|
committer | Christopher Haster <chaster@utexas.edu> | 2017-10-18 08:44:30 +0300 |
commit | 46e22b2a383528b0733971f8f84550bc6754b939 (patch) | |
tree | 94a0ac58cd714ec9cffca89339205b9a629494ad /lfs.c | |
parent | 4fdca15a0d938ac93e734f444a18ed1d3770a3ff (diff) |
Adopted lfs_ctz_index implementation using popcount
This reduces the O(n^2logn) runtime to read a file to only O(nlog).
The extra O(n) did not touch the disk, so it isn't a problem until the
files become very large, but this solution comes with very little cost.
Long story short, you can find the block index + offset pair for a
CTZ linked-list with this series of formulas:
n' = floor(N / (B - 2w/8))
N' = (B - 2w/8)n' + (w/8)popcount(n')
off' = N - N'
n, off =
n'-1, off'+B if off' < 0
n', off'+(w/8)(ctz(n')+1) if off' >= 0
For the long story, you will need to see the updated DESIGN.md
Diffstat (limited to 'lfs.c')
-rw-r--r-- | lfs.c | 21 |
1 files changed, 14 insertions, 7 deletions
@@ -1004,15 +1004,22 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) { /// File index list operations /// static int lfs_ctz_index(lfs_t *lfs, lfs_off_t *off) { - lfs_off_t i = 0; - - while (*off >= lfs->cfg->block_size) { - i += 1; - *off -= lfs->cfg->block_size; - *off += 4*(lfs_ctz(i) + 1); + lfs_off_t size = *off; + lfs_off_t i = size / (lfs->cfg->block_size-2*4); + if (i == 0) { + return 0; } - return i; + lfs_off_t nsize = (lfs->cfg->block_size-2*4)*i + 4*lfs_popc(i-1) + 2*4; + lfs_soff_t noff = size - nsize; + + if (noff < 0) { + *off = noff + lfs->cfg->block_size; + return i-1; + } else { + *off = noff + 4*(lfs_ctz(i) + 1); + return i; + } } static int lfs_ctz_find(lfs_t *lfs, |