#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <bstrlib.h>
#include <atalk/cnid.h>
#include <atalk/directory.h>
#include <atalk/globals.h>
#include <atalk/logger.h>
#include <atalk/queue.h>
#include <atalk/util.h>
#include <atalk/volume.h>
#include "dircache.h"
#include "directory.h"
#include "hash.h"
Data Structures | |
struct | dircache_stat |
Macros | |
#define | get16bits(d) |
Functions | |
static hash_val_t | hash_vid_did (const void *key) |
static int | hash_comp_vid_did (const void *key1, const void *key2) |
static hash_val_t | hash_didname (const void *p) |
static int | hash_comp_didname (const void *k1, const void *k2) |
static int | should_validate_cache_entry (void) |
Determine if cache entry should be validated against filesystem. | |
static int | cache_entry_externally_modified (struct dir *cdir, const struct stat *st) |
Smart validation for directory cache entries. | |
static void | dircache_evict (void) |
Remove a fixed number of (oldest) entries from the cache and indexes. | |
struct dir * | dircache_search_by_did (const struct vol *vol, cnid_t cnid) |
Search the dircache via a CNID for a directory. | |
struct dir * | dircache_search_by_name (const struct vol *vol, const struct dir *dir, char *name, int len) |
Search the cache via did/name hashtable. | |
int | dircache_add (const struct vol *vol, struct dir *dir) |
create struct dir from struct path | |
void | dircache_remove (const struct vol *vol _U_, struct dir *dir, int flags) |
Remove an entry from the dircache. | |
void | dircache_remove_children (const struct vol *vol, struct dir *dir) |
Remove all child entries of a directory from the dircache. | |
int | dircache_init (int reqsize) |
Initialize the dircache and indexes. | |
void | log_dircache_stat (void) |
Log dircache statistics. | |
void | dircache_dump (void) |
Dump dircache to /tmp/dircache.PID. | |
int | dircache_set_validation_params (unsigned int freq, unsigned int meta_win, unsigned int meta_thresh) |
Set directory cache validation parameters. | |
void | dircache_reset_validation_counter (void) |
Reset validation counter for consistent testing. | |
void | dircache_report_invalid_entry (struct dir *dir) |
Report that a cache entry was invalid when actually used. |
Variables | |
static hash_t * | dircache |
static unsigned int | dircache_maxsize |
static unsigned int | dircache_validation_freq = DEFAULT_DIRCACHE_VALIDATION_FREQ |
static unsigned int | dircache_metadata_window = DEFAULT_DIRCACHE_METADATA_WINDOW |
static unsigned int | dircache_metadata_threshold |
static volatile uint64_t | validation_counter = 0 |
static struct dircache_stat | dircache_stat |
static hash_t * | index_didname |
static q_t * | index_queue |
static unsigned long | queue_count |
#define get16bits | ( | d | ) |
|
static |
Smart validation for directory cache entries.
Distinguishes between metadata-only changes (permissions, xattrs) and content changes (files added/removed) to avoid unnecessary cache invalidation. This is critical for AFP performance as directory ctime changes frequently for reasons that don't affect cached directory information.
cdir | (r) cached directory entry |
st | (r) fresh stat information from filesystem |
create struct dir from struct path
Add a struct dir to the cache and its indexes.
dir | (r) pointer to parrent directory |
void dircache_dump | ( | void | ) |
Dump dircache to /tmp/dircache.PID.
|
static |
Remove a fixed number of (oldest) entries from the cache and indexes.
The default is to remove the 256 oldest entries from the cache.
int dircache_init | ( | int | reqsize | ) |
Initialize the dircache and indexes.
This is called in child afpd initialisation. The maximum cache size will be max(DEFAULT_MAX_DIRCACHE_SIZE, min(size, MAX_POSSIBLE_DIRCACHE_SIZE)). It initializes a hashtable which we use to store a directory cache in. It also initializes two indexes:
size | (r) requested maximum size from afp.conf |
Remove an entry from the dircache.
Callers outside of dircache.c should call this with flags = QUEUE_INDEX | DIDNAME_INDEX | DIRCACHE.
Remove all child entries of a directory from the dircache.
When a directory is renamed or moved, the full paths stored in the dircache become invalid for all child entries of the renamed dir. This function prunes orphaned child dircache entries of given dir. CNID entries use parent DIDs and name, and requre recursion to get the full path, therefore parent changes do not invalidate the CNIDs.
vol | (r) volume |
dir | (r) parent directory whose children should be removed |
void dircache_report_invalid_entry | ( | struct dir * | dir | ) |
Report that a cache entry was invalid when actually used.
This function should be called when a cached directory entry that was returned without validation (for performance) turns out to be invalid when actually accessed (e.g., file doesn't exist, has been modified, etc). This helps track the effectiveness of the validation frequency setting.
dir | (r) The directory entry that was found to be invalid |
void dircache_reset_validation_counter | ( | void | ) |
Reset validation counter for consistent testing.
Resets the global validation counter to ensure predictable validation patterns between test runs or configuration changes.
Search the dircache via a CNID for a directory.
Found cache entries are expunged if both the parent directory st_ctime and the objects st_ctime are modified. This func builds on the fact, that all our code only ever needs to and does search the dircache by CNID expecting directories to be returned, but not files. Thus (1) if we find a file for a given CNID we (1a) remove it from the cache (1b) return NULL indicating nothing found (2) we can then use d_fullpath to stat the directory
vol | (r) pointer to struct vol |
cnid | (r) CNID of the directory to search |
struct dir * dircache_search_by_name | ( | const struct vol * | vol, |
const struct dir * | dir, | ||
char * | name, | ||
int | len ) |
Search the cache via did/name hashtable.
Found cache entries are expunged if both the parent directory st_ctime and the objects st_ctime are modified.
vol | (r) volume |
dir | (r) directory |
name | (r) name (server side encoding) @parma len (r) strlen of name |
int dircache_set_validation_params | ( | unsigned int | freq, |
unsigned int | meta_win, | ||
unsigned int | meta_thresh ) |
Set directory cache validation parameters.
Allows runtime configuration of cache validation behavior for performance tuning. Lower validation frequency improves performance but may delay detection of external filesystem changes.
freq | (r) validation frequency (1 = validate every access, 5 = every 5th access) |
meta_win | (r) metadata change time window in seconds |
meta_thresh | (r) metadata change threshold in seconds |
|
static |
|
static |
|
static |
|
static |
void log_dircache_stat | ( | void | ) |
Log dircache statistics.
Includes hit ratio percentage for monitoring cache effectiveness, validation-specific metrics to monitor performance impact of the optimization changes, and username for tracking per-user stats. Shows both expunged (caught by validation) and invalid_on_use (missed by validation).
|
static |
Determine if cache entry should be validated against filesystem.
Uses probabilistic validation to reduce filesystem calls while still detecting external changes. Internal netatalk operations use explicit cache invalidation via dir_remove() calls, so frequent validation is only needed to detect external filesystem changes.
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |