Project

General

Profile

Download (4.23 KB) Statistics
| Branch: | Tag: | Revision:
7e8045d8 David Sorber
/**
* Copyright © 2019, Oracle and/or its affiliates. All rights reserved.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl
*
*/
/* Maintain a set of inodes */
#include "inodemap.h"
#include "malloc.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>

struct entry {
bool valid;
dev_t dev;
ino_t inode;
void *value;
};

struct inodemap {
size_t n_entries;
size_t hash_size;
struct entry *entries;
};

struct inodemap *mk_inodemap(void) {
size_t initial_hash_size = 2;
struct inodemap *MALLOC(result);
struct entry *MALLOC_N(entries, initial_hash_size);
*result = (struct inodemap){.n_entries = 0,
.hash_size = initial_hash_size,
.entries = entries};
for (size_t i = 0; i < initial_hash_size; i++) {
entries[i].valid = false;
}
return result;
}

struct inodemap *inodemap_destroy(struct inodemap *is,
void (*destroy_value_fun)(void*)) {
assert(is);
for (size_t i = 0; i < is->hash_size; i++) {
if (is->entries[i].valid) {
destroy_value_fun(is->entries[i].value);
}
}
free(is->entries);
free(is);
return NULL;
}

static const uint64_t FNV_OFFSET = 14695981039346656037ull;
static const uint64_t FNV_PRIME = 1099511628211ull;

static uint64_t hash128(uint64_t a, uint64_t b) {
uint64_t hash = FNV_OFFSET;
for (size_t i = 0; i < 8; i++) {
hash ^= (a>>(i*8))&0xFFul;
hash *= FNV_PRIME;
hash ^= (b>>(i*8))&0xFFul;
hash *= FNV_PRIME;
}
return hash;
}

uint64_t inodemap_hash(dev_t dev, ino_t inode) {
return hash128(dev, inode);
}

static struct entry *
find_entry(struct entry *entries, size_t hash_size, dev_t dev, ino_t ino) {
// hash_size must be a power of two
assert(0 == (hash_size & (hash_size - 1)));
uint64_t h = inodemap_hash(dev, ino);
for (size_t i = 0; i < hash_size; i++) {
size_t idx = ((size_t)h + i) & (hash_size-1);
if (!entries[idx].valid
|| (entries[idx].dev == dev && entries[idx].inode == ino)) {
return entries+idx;
}
}
assert(0);
}

bool
inodemap_lookup(struct inodemap *im,
dev_t dev,
ino_t inode,
void const **value) {
struct entry *e = find_entry(im->entries, im->hash_size, dev, inode);
if (e->valid) {
*value = e->value;
}
return e->valid;

}

static void
maybe_grow_table(struct inodemap *im) {
if (im->n_entries * 2 < im->hash_size) {
return;
}
size_t new_size = 2*im->hash_size;
struct entry *MALLOC_N(new_entries, new_size);
for (size_t i = 0; i < new_size; i++) {
new_entries[i].valid = false;
}
for (size_t i = 0; i < im->hash_size; i++) {
if (im->entries[i].valid) {
struct entry *e = find_entry(new_entries, new_size,
im->entries[i].dev,
im->entries[i].inode);
assert(!e->valid);
*e = im->entries[i];
}
}
free(im->entries);
im->entries = new_entries;
im->hash_size = new_size;
}

static void
inodemap_print(struct inodemap *im, FILE *f)
__attribute__((unused));
static void
inodemap_print(struct inodemap *im, FILE *f) {
fprintf(f, "Inode map %p. n_entries=%zd hash_size=%zd\n",
im, im->n_entries, im->hash_size);
for (size_t i = 0 ; i < im->hash_size; i++) {
if (im->entries[i].valid) {
fprintf(f, "%zd: %lu,%lu -> %p\n", i,
im->entries[i].dev, im->entries[i].inode,
im->entries[i].value);
} else {
fprintf(f, "%zd: empty\n", i);
}
}
}

void
inodemap_insert(struct inodemap *im, dev_t dev, ino_t inode, void *value) {
maybe_grow_table(im);
// Now we know we have space.
struct entry *e = find_entry(im->entries, im->hash_size, dev, inode);
assert(!e->valid);
*e = (struct entry){.valid = true,
.dev = dev,
.inode = inode,
.value = value};
im->n_entries++;
}