mirror of
https://github.com/jarun/nnn.git
synced 2024-11-28 05:41:31 +00:00
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.
This commit is contained in:
parent
b63c00c9af
commit
547d87bfc2
65
src/nnn.c
65
src/nnn.c
|
@ -186,6 +186,7 @@ typedef unsigned int uint;
|
||||||
typedef unsigned char uchar;
|
typedef unsigned char uchar;
|
||||||
typedef unsigned short ushort;
|
typedef unsigned short ushort;
|
||||||
typedef long long ll;
|
typedef long long ll;
|
||||||
|
typedef unsigned long long ull;
|
||||||
|
|
||||||
/* STRUCTURES */
|
/* STRUCTURES */
|
||||||
|
|
||||||
|
@ -195,6 +196,7 @@ typedef struct entry {
|
||||||
time_t t;
|
time_t t;
|
||||||
off_t size;
|
off_t size;
|
||||||
blkcnt_t blocks; /* number of 512B blocks allocated */
|
blkcnt_t blocks; /* number of 512B blocks allocated */
|
||||||
|
ino_t inode;
|
||||||
mode_t mode;
|
mode_t mode;
|
||||||
ushort nlen; /* Length of file name; can be uchar (< NAME_MAX + 1) */
|
ushort nlen; /* Length of file name; can be uchar (< NAME_MAX + 1) */
|
||||||
uchar flags; /* Flags specific to the file */
|
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 */
|
/* Buffer to store plugins control pipe location */
|
||||||
static char g_pipepath[TMP_LEN_MAX] __attribute__ ((aligned));
|
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 */
|
/* Plugin control initialization status */
|
||||||
static bool g_plinit = FALSE;
|
static bool g_plinit = FALSE;
|
||||||
|
|
||||||
|
@ -573,6 +580,43 @@ static inline bool getutil(char *util);
|
||||||
|
|
||||||
/* Functions */
|
/* 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)
|
static void sigint_handler(int sig)
|
||||||
{
|
{
|
||||||
(void) sig;
|
(void) sig;
|
||||||
|
@ -989,6 +1033,8 @@ static void endselection(void)
|
||||||
if (cfg.selmode) {
|
if (cfg.selmode) {
|
||||||
cfg.selmode = 0;
|
cfg.selmode = 0;
|
||||||
|
|
||||||
|
clear_hash();
|
||||||
|
|
||||||
if (selbufpos) { /* File path(s) written to the buffer */
|
if (selbufpos) { /* File path(s) written to the buffer */
|
||||||
writesel(pselbuf, selbufpos - 1); /* Truncate NULL from end */
|
writesel(pselbuf, selbufpos - 1); /* Truncate NULL from end */
|
||||||
spawn(copier, NULL, NULL, NULL, F_NOTRACE);
|
spawn(copier, NULL, NULL, NULL, F_NOTRACE);
|
||||||
|
@ -1076,8 +1122,7 @@ static bool editselection(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
nselected = lines;
|
nselected = lines;
|
||||||
writesel(pselbuf, selbufpos - 1);
|
endselection();
|
||||||
spawn(copier, NULL, NULL, NULL, F_NOTRACE);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -3617,6 +3662,7 @@ static int dentfill(char *path, struct entry **dents)
|
||||||
* Known drawbacks:
|
* Known drawbacks:
|
||||||
* - the symlink size is set to 0
|
* - the symlink size is set to 0
|
||||||
* - the modification time of the symlink is set to that of the target file
|
* - 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;
|
flags = AT_SYMLINK_NOFOLLOW;
|
||||||
}
|
}
|
||||||
|
@ -3724,6 +3770,7 @@ static int dentfill(char *path, struct entry **dents)
|
||||||
|
|
||||||
/* Copy other fields */
|
/* Copy other fields */
|
||||||
dentp->t = cfg.mtime ? sb.st_mtime : sb.st_atime;
|
dentp->t = cfg.mtime ? sb.st_mtime : sb.st_atime;
|
||||||
|
dentp->inode = sb.st_ino;
|
||||||
#ifndef __sun
|
#ifndef __sun
|
||||||
if (!flags && dp->d_type == DT_LNK) {
|
if (!flags && dp->d_type == DT_LNK) {
|
||||||
/* Do not add sizes for links */
|
/* Do not add sizes for links */
|
||||||
|
@ -4740,7 +4787,7 @@ nochange:
|
||||||
rangesel = FALSE;
|
rangesel = FALSE;
|
||||||
|
|
||||||
/* Do not select if already selected */
|
/* 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));
|
appendfpath(newpath, mkpath(path, dents[cur].name, newpath));
|
||||||
|
|
||||||
++nselected;
|
++nselected;
|
||||||
|
@ -4802,11 +4849,15 @@ nochange:
|
||||||
selendid = ndents - 1;
|
selendid = ndents - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (r = selstartid; r <= selendid; ++r)
|
for (r = selstartid; r <= selendid; ++r) {
|
||||||
if (!(dents[r].flags & FILE_SELECTED)) {
|
if (test_set_bit((ull)dents[r].inode)) {
|
||||||
appendfpath(newpath, mkpath(path, dents[r].name, newpath));
|
appendfpath(newpath, mkpath(path, dents[r].name, newpath));
|
||||||
dents[r].flags |= FILE_SELECTED;
|
dents[r].flags |= FILE_SELECTED;
|
||||||
++nselected;
|
++nselected;
|
||||||
|
} else {
|
||||||
|
DPRINTF_S(dents[r].name);
|
||||||
|
DPRINTF_U(dents[r].inode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Show the range count */
|
/* Show the range count */
|
||||||
|
@ -5444,6 +5495,7 @@ static void cleanup(void)
|
||||||
free(initpath);
|
free(initpath);
|
||||||
free(bmstr);
|
free(bmstr);
|
||||||
free(pluginstr);
|
free(pluginstr);
|
||||||
|
free(ihashbmp);
|
||||||
|
|
||||||
unlink(g_pipepath);
|
unlink(g_pipepath);
|
||||||
|
|
||||||
|
@ -5742,6 +5794,9 @@ int main(int argc, char *argv[])
|
||||||
if (!initcurses(&mask))
|
if (!initcurses(&mask))
|
||||||
return _FAILURE;
|
return _FAILURE;
|
||||||
|
|
||||||
|
ihashbmp = malloc(HASH_OCTETS << 3);
|
||||||
|
memset(ihashbmp, 0, HASH_OCTETS << 3);
|
||||||
|
|
||||||
browse(initpath, session);
|
browse(initpath, session);
|
||||||
mousemask(mask, NULL);
|
mousemask(mask, NULL);
|
||||||
exitcurses();
|
exitcurses();
|
||||||
|
|
Loading…
Reference in a new issue