summaryrefslogtreecommitdiff
path: root/src/cache/backings/file_mapped.c
blob: 7657a21e0c8b49f05f5db0d0910952cc926ef4b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include "file.h"
#include "file_common.h"

static void file_backing_lock(struct cch_backing *backing)
{
    struct cch_backing_file *file = (struct cch_backing_file *)backing;
    nn_mutex_lock(&file->mutex);
}

static void file_backing_write(struct cch_backing *backing, u8 *buf, off_t index, size_t *count)
{
    struct cch_backing_file *file = (struct cch_backing_file *)backing;
    off_t n = (off_t)*count;
    nn_mutex_lock(&file->mutex);
    off_t size = file->backing.size;
    if (size > 0 && index + n >= size) {
        n = MAX(size - index, (off_t)0);
    }
    if (n > 0) {
        al_memcpy(file->u.map + index, buf, n);
        cch_backing_fill_range(&file->backing, index, n);
    }
    *count = (size_t)n;
    nn_mutex_unlock(&file->mutex);
}

static u8 *file_backing_get_ptr(struct cch_backing *backing, off_t index, size_t *count)
{
    struct cch_backing_file *file = (struct cch_backing_file *)backing;
    off_t n = (off_t)*count;
    nn_mutex_lock(&file->mutex);
    off_t size = file->backing.size;
    if (size > 0 && index + n >= size) {
        n = MAX(size - index, (off_t)0);
    }
    *count = (size_t)n;
    return (u8 *)(file->u.map + index);
}

static void file_backing_unlock(struct cch_backing *backing)
{
    struct cch_backing_file *file = (struct cch_backing_file *)backing;
    nn_mutex_unlock(&file->mutex);
}

static void file_backing_set_size(struct cch_backing *backing, off_t size, bool expand_to_size)
{
    struct cch_backing_file *file = (struct cch_backing_file *)backing;
    al_assert(expand_to_size || size == 0);
    nn_mutex_lock(&file->mutex);
    file->backing.size = size;
    if ((size_t)size > file->file.size) {
        nn_file_munmap(&file->file, file->u.map);
        nn_file_truncate(&file->file, size);
        file->u.map = nn_file_mmap(&file->file);
        file->file.size = size;
    }
    nn_mutex_unlock(&file->mutex);
}

static void file_backing_free(struct cch_backing **backing)
{
    struct cch_backing_file *file = (struct cch_backing_file *)*backing;
    nn_file_munmap(&file->file, file->u.map);
    nn_file_close(&file->file);
    al_array_free(file->backing.available);
    al_free(file);
    *backing = NULL;
}

struct cch_backing *cch_backing_file_create(str *path, size_t size)
{
    struct cch_backing_file *file = al_alloc_object(struct cch_backing_file);
    file->backing.mode = CACHE_BACKING_MAPPED;
    file->backing.size = -1;
    file->backing.lock = file_backing_lock;
    file->backing.write = file_backing_write;
    file->backing.read = NULL;
    file->backing.get_ptr = file_backing_get_ptr;
    file->backing.unlock = file_backing_unlock;
    file->backing.set_size = file_backing_set_size;
    file->backing.get_size_if_known = file_backing_get_size_if_known;
    file->backing.finalize = file_backing_finalize;
    file->backing.free = file_backing_free;
    al_array_init(file->backing.available);
    if (!file_open_internal(file, path, size)) {
        goto err;
    }
    if (!(file->u.map = nn_file_mmap(&file->file))) {
        nn_file_close(&file->file);
        goto err;
    }
    nn_mutex_init(&file->mutex);
    return (struct cch_backing *)file;
err:
    al_free(file);
    return NULL;
}