summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSadeep Madurange <sadeep@asciimx.com>2026-03-03 21:59:48 +0800
committerSadeep Madurange <sadeep@asciimx.com>2026-03-03 22:09:00 +0800
commit5b20837cf59157f77d6bd49bc021d2be3479610f (patch)
tree468cd2a7be6f40ecb928574b17a64363ee114e1c
parent5a9973f55d239fc92a17daea9a1e89beac827670 (diff)
downloadcvn-5b20837cf59157f77d6bd49bc021d2be3479610f.tar.gz
Use dynamic stack and ignore repo in traverse().
-rw-r--r--main.c48
1 files changed, 32 insertions, 16 deletions
diff --git a/main.c b/main.c
index f709768..97083ba 100644
--- a/main.c
+++ b/main.c
@@ -13,13 +13,11 @@
#define REPO ".cvn"
#define INDEX "index"
-#define MAX_SUBDIRS 256
-
static inline void init(int argc, char *argv[]);
static inline void status(int argc, char *argv[]);
-/* helpers */
static inline void traverse(void);
+static inline uint8_t ignore(const char *path);
struct command {
char *name;
@@ -99,20 +97,34 @@ static inline void status(int argc, char *argv[])
traverse();
}
+static inline uint8_t ignore(const char *path)
+{
+ return strcmp(path, ".") == 0 ||
+ strcmp(path, "..") == 0 ||
+ strcmp(path, REPO) == 0;
+}
+
static inline void traverse(void)
{
DIR *dir;
char *path, *rel_path;
struct stat st;
struct dirent *entry;
- int subdirs_len;
- char *subdirs[MAX_SUBDIRS];
-
- subdirs_len = 0;
- subdirs[subdirs_len++] = strdup(".");
-
- while (subdirs_len) {
- path = subdirs[--subdirs_len];
+ int i, subdirs_len;
+ char **subdirs;
+
+ i = 0;
+ // On 64-bit systems: 512 * 8 (ptr size) = 4096 - typical page size / 64 cache lines
+ // Page-aligned buffers that fit in CPU cache lines reduce mmu overhead (play well
+ // with the CPU's TLB (Tranlation Lookaside Buffer).
+ subdirs_len = 512;
+ subdirs = malloc(sizeof(subdirs[0]) * subdirs_len);
+ if (!subdirs)
+ err(1, "malloc() failed");
+ subdirs[i++] = strdup(".");
+
+ while (i > 0) {
+ path = subdirs[--i];
if (!(dir = opendir(path))) {
warn("Failed to open directory %s", path);
free(path);
@@ -120,7 +132,7 @@ static inline void traverse(void)
}
while ((entry = readdir(dir)) != NULL) {
- if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+ if (ignore(entry->d_name))
continue;
if (asprintf(&rel_path, "%s/%s", path, entry->d_name) == -1)
err(1, "asprintf() failed");
@@ -130,16 +142,20 @@ static inline void traverse(void)
continue;
}
if (S_ISDIR(st.st_mode)) {
- if (subdirs_len >= MAX_SUBDIRS)
- errx(1, "Repository too large: directory tree too deep/wide");
- subdirs[subdirs_len++] = rel_path;
+ if (i >= subdirs_len) {
+ subdirs_len <<= 1;
+ subdirs = realloc(subdirs, sizeof(subdirs[0]) * subdirs_len);
+ if (!subdirs)
+ err(1, "realloc() failed");
+ }
+ subdirs[i++] = rel_path;
} else {
printf("File: %s\n", rel_path);
free(rel_path);
}
}
-
free(path);
closedir(dir);
}
+ free(subdirs);
}