mirror of
https://github.com/trapexit/mergerfs.git
synced 2024-12-02 05:23:41 +08:00
225 lines
4.5 KiB
C
225 lines
4.5 KiB
C
#include "fuse_node.h"
|
|
|
|
#include "khash.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include <stdio.h> // for debugging
|
|
|
|
#define UNKNOWN_INO UINT64_MAX
|
|
#define ROOT_NODE_ID 0
|
|
#define ROOT_NODE_NAME "/"
|
|
|
|
typedef struct node_idname_t node_idname_t;
|
|
struct node_idname_t
|
|
{
|
|
uint64_t id;
|
|
const char *name;
|
|
};
|
|
|
|
static khint_t idname_hash_func(const node_idname_t idname);
|
|
static int idname_hash_equal(const node_idname_t idname0, const node_idname_t idname1);
|
|
|
|
KHASH_INIT(node,node_idname_t,fuse_node_t*,1,idname_hash_func,idname_hash_equal);
|
|
|
|
typedef struct fuse_node_hashtable_t fuse_node_hashtable_t;
|
|
struct fuse_node_hashtable_t
|
|
{
|
|
kh_node_t *ht;
|
|
uint64_t id;
|
|
uint64_t generation;
|
|
};
|
|
|
|
static
|
|
inline
|
|
khint_t
|
|
idname_hash_func(const node_idname_t idname_)
|
|
{
|
|
if(idname_.name == NULL)
|
|
return idname_.id;
|
|
return (idname_.id ^ kh_str_hash_func(idname_.name));
|
|
}
|
|
|
|
static
|
|
inline
|
|
int
|
|
idname_hash_equal(const node_idname_t idname0_,
|
|
const node_idname_t idname1_)
|
|
{
|
|
return ((idname0_.id == idname1_.id) &&
|
|
((idname0_.name == idname1_.name) ||
|
|
(strcmp(idname0_.name,idname1_.name) == 0)));
|
|
}
|
|
|
|
static
|
|
inline
|
|
fuse_node_t*
|
|
fuse_node_alloc(const uint64_t id_,
|
|
const char *name_)
|
|
{
|
|
fuse_node_t *node;
|
|
|
|
node = (fuse_node_t*)calloc(1,sizeof(fuse_node_t));
|
|
|
|
node->id = id_;
|
|
node->name = strdup(name_);
|
|
node->ref_count = 1;
|
|
node->lookup_count = 1;
|
|
|
|
return node;
|
|
}
|
|
|
|
static
|
|
inline
|
|
void
|
|
fuse_node_free(fuse_node_t *node_)
|
|
{
|
|
free(node_->name);
|
|
free(node_);
|
|
}
|
|
|
|
static
|
|
inline
|
|
uint64_t
|
|
rand64()
|
|
{
|
|
uint64_t rv;
|
|
|
|
rv = rand();
|
|
rv <<= 32;
|
|
rv |= rand();
|
|
|
|
return rv;
|
|
}
|
|
|
|
static
|
|
inline
|
|
void
|
|
node_hashtable_gen_unique_id(fuse_node_hashtable_t *ht_)
|
|
{
|
|
do
|
|
{
|
|
ht_->id++;
|
|
if(ht_->id == 0)
|
|
ht_->generation++;
|
|
}
|
|
while((ht_->id == 0) || (ht_->id == UNKNOWN_INO));
|
|
}
|
|
|
|
static
|
|
inline
|
|
void
|
|
node_hashtable_put_root(fuse_node_hashtable_t *ht_)
|
|
{
|
|
int rv;
|
|
khint_t k;
|
|
fuse_node_t *root_node;
|
|
const node_idname_t idname0 = {ROOT_NODE_ID,""};
|
|
const node_idname_t idname1 = {ROOT_NODE_ID,ROOT_NODE_NAME};
|
|
|
|
root_node = fuse_node_alloc(ROOT_NODE_ID,ROOT_NODE_NAME);
|
|
|
|
k = kh_put_node(ht_->ht,idname0,&rv);
|
|
kh_value(ht_->ht,k) = root_node;
|
|
|
|
k = kh_put_node(ht_->ht,idname1,&rv);
|
|
kh_value(ht_->ht,k) = root_node;
|
|
}
|
|
|
|
static
|
|
inline
|
|
void
|
|
node_hashtable_set_id_gen(fuse_node_hashtable_t *ht_,
|
|
fuse_node_t *node_)
|
|
{
|
|
node_hashtable_gen_unique_id(ht_);
|
|
node_->id = ht_->id;
|
|
node_->generation = ht_->generation;
|
|
}
|
|
|
|
fuse_node_hashtable_t*
|
|
fuse_node_hashtable_init()
|
|
{
|
|
fuse_node_hashtable_t *ht;
|
|
|
|
ht = (fuse_node_hashtable_t*)calloc(sizeof(fuse_node_hashtable_t),1);
|
|
if(ht == NULL)
|
|
return NULL;
|
|
|
|
ht->ht = kh_init_node();
|
|
if(ht->ht == NULL)
|
|
{
|
|
free(ht);
|
|
return NULL;
|
|
}
|
|
|
|
srand(time(NULL));
|
|
ht->id = 0;
|
|
ht->generation = rand64();
|
|
|
|
node_hashtable_put_root(ht);
|
|
|
|
return ht;
|
|
}
|
|
|
|
fuse_node_t*
|
|
fuse_node_hashtable_put(fuse_node_hashtable_t *ht_,
|
|
const uint64_t parent_id_,
|
|
const uint64_t child_id_,
|
|
const char *child_name_)
|
|
{
|
|
int rv;
|
|
khint_t k;
|
|
fuse_node_t *child_node;
|
|
const node_idname_t p_idname = {parent_id_,""};
|
|
const node_idname_t c0_idname = {child_id_,child_name_};
|
|
const node_idname_t c1_idname = {parent_id_,child_name_};
|
|
|
|
child_node = fuse_node_alloc(child_id_,child_name_);
|
|
|
|
k = kh_get_node(ht_->ht,p_idname);
|
|
child_node->parent = kh_value(ht_->ht,k);
|
|
child_node->parent->ref_count++;
|
|
|
|
k = kh_put_node(ht_->ht,c0_idname,&rv);
|
|
kh_value(ht_->ht,k) = child_node;
|
|
|
|
k = kh_put_node(ht_->ht,c1_idname,&rv);
|
|
kh_value(ht_->ht,k) = child_node;
|
|
|
|
return child_node;
|
|
}
|
|
|
|
fuse_node_t*
|
|
fuse_node_hashtable_get(fuse_node_hashtable_t *ht_,
|
|
const uint64_t id_)
|
|
{
|
|
return fuse_node_hashtable_get_child(ht_,id_,"");
|
|
}
|
|
|
|
fuse_node_t*
|
|
fuse_node_hashtable_get_child(fuse_node_hashtable_t *ht_,
|
|
const uint64_t parent_id_,
|
|
const char *child_name_)
|
|
{
|
|
khint_t k;
|
|
fuse_node_t *node;
|
|
const node_idname_t idname = {parent_id_,child_name_};
|
|
|
|
k = kh_get_node(ht_->ht,idname);
|
|
node = ((k != kh_end(ht_->ht)) ?
|
|
kh_value(ht_->ht,k) :
|
|
NULL);
|
|
|
|
return node;
|
|
}
|
|
|
|
void
|
|
fuse_node_hashtable_del(fuse_node_hashtable_t *ht_,
|
|
fuse_node_t *node_)
|
|
{
|
|
|
|
}
|