diff options
author | Arun Prakash Jana <engineerarun@gmail.com> | 2019-11-23 09:46:24 +0530 |
---|---|---|
committer | Arun Prakash Jana <engineerarun@gmail.com> | 2019-11-23 10:05:06 +0530 |
commit | 547d87bfc2caf276dd1bcb943677a0ca306c602d (patch) | |
tree | 92048020ab06ab8292908bdc2d2c996dceb7e6dd /src/nnn.c | |
parent | b63c00c9af55e7a28cf415ced1015caa74f1b829 (diff) | |
download | nnn-547d87bfc2caf276dd1bcb943677a0ca306c602d.tar.gz |
Indicative inode hash bitmap implementation. Read details.
Known issues:
- To optimize dentfill() on most architectures we don't fstatat() with
AT_SYMLINK_NOFOLLOW to get the inode number of the symlink itself.
- The current hash size serves the purpose of one filesystem. To serve
more and have unique bits, we have to add more bits to prefix dev ID
to the inode. Memory consumption will be significant.
This will be reverted in next commit.
Diffstat (limited to 'src/nnn.c')
-rw-r--r-- | src/nnn.c | 65 |
1 files changed, 60 insertions, 5 deletions
@@ -186,6 +186,7 @@ typedef unsigned int uint; typedef unsigned char uchar; typedef unsigned short ushort; typedef long long ll; +typedef unsigned long long ull; /* STRUCTURES */ @@ -195,6 +196,7 @@ typedef struct entry { time_t t; off_t size; blkcnt_t blocks; /* number of 512B blocks allocated */ + ino_t inode; mode_t mode; ushort nlen; /* Length of file name; can be uchar (< NAME_MAX + 1) */ uchar flags; /* Flags specific to the file */ @@ -345,6 +347,11 @@ static char g_tmpfpath[TMP_LEN_MAX] __attribute__ ((aligned)); /* Buffer to store plugins control pipe location */ static char g_pipepath[TMP_LEN_MAX] __attribute__ ((aligned)); +#define HASH_BITS (0xFFFFFF) +#define HASH_OCTETS (HASH_BITS >> 6) +/* Buffer to hold inode hash bit for selection */ +static ull *ihashbmp; + /* Plugin control initialization status */ static bool g_plinit = FALSE; @@ -573,6 +580,43 @@ static inline bool getutil(char *util); /* Functions */ +/* + * Source: https://elixir.bootlin.com/linux/latest/source/arch/alpha/include/asm/bitops.h#L314 + */ +static bool test_set_bit(ull nr) +{ + ull *m = ((ull *)ihashbmp) + (nr >> 6); + + if (*m & (1 << (nr & 63))) + return FALSE; + + *m |= 1 << (nr & 63); + + return TRUE; +} +#if 0 +static bool test_clear_bit(ull nr) +{ + ull *m = ((ull *) ihashbmp) + (nr >> 6); + + if (!(*m & (1 << (nr & 63)))) + return FALSE; + + *m &= ~(1 << (nr & 63)); + return TRUE; +} +#endif + +static void clear_hash() +{ + ulong i = 0; + ull *addr = ihashbmp; + + for (; i < HASH_OCTETS; ++i, ++addr) + if (*addr) + *addr = 0; +} + static void sigint_handler(int sig) { (void) sig; @@ -989,6 +1033,8 @@ static void endselection(void) if (cfg.selmode) { cfg.selmode = 0; + clear_hash(); + if (selbufpos) { /* File path(s) written to the buffer */ writesel(pselbuf, selbufpos - 1); /* Truncate NULL from end */ spawn(copier, NULL, NULL, NULL, F_NOTRACE); @@ -1076,8 +1122,7 @@ static bool editselection(void) } nselected = lines; - writesel(pselbuf, selbufpos - 1); - spawn(copier, NULL, NULL, NULL, F_NOTRACE); + endselection(); return TRUE; @@ -3617,6 +3662,7 @@ static int dentfill(char *path, struct entry **dents) * Known drawbacks: * - the symlink size is set to 0 * - the modification time of the symlink is set to that of the target file + * - the inode number is that of the target file */ flags = AT_SYMLINK_NOFOLLOW; } @@ -3724,6 +3770,7 @@ static int dentfill(char *path, struct entry **dents) /* Copy other fields */ dentp->t = cfg.mtime ? sb.st_mtime : sb.st_atime; + dentp->inode = sb.st_ino; #ifndef __sun if (!flags && dp->d_type == DT_LNK) { /* Do not add sizes for links */ @@ -4740,7 +4787,7 @@ nochange: rangesel = FALSE; /* Do not select if already selected */ - if (!(dents[cur].flags & FILE_SELECTED)) { + if (test_set_bit((ull)dents[cur].inode)) { appendfpath(newpath, mkpath(path, dents[cur].name, newpath)); ++nselected; @@ -4802,12 +4849,16 @@ nochange: selendid = ndents - 1; } - for (r = selstartid; r <= selendid; ++r) - if (!(dents[r].flags & FILE_SELECTED)) { + for (r = selstartid; r <= selendid; ++r) { + if (test_set_bit((ull)dents[r].inode)) { appendfpath(newpath, mkpath(path, dents[r].name, newpath)); dents[r].flags |= FILE_SELECTED; ++nselected; + } else { + DPRINTF_S(dents[r].name); + DPRINTF_U(dents[r].inode); } + } /* Show the range count */ //r = selendid - selstartid + 1; @@ -5444,6 +5495,7 @@ static void cleanup(void) free(initpath); free(bmstr); free(pluginstr); + free(ihashbmp); unlink(g_pipepath); @@ -5742,6 +5794,9 @@ int main(int argc, char *argv[]) if (!initcurses(&mask)) return _FAILURE; + ihashbmp = malloc(HASH_OCTETS << 3); + memset(ihashbmp, 0, HASH_OCTETS << 3); + browse(initpath, session); mousemask(mask, NULL); exitcurses(); |