summaryrefslogtreecommitdiff
path: root/src/sortedcache.h
blob: 4cacad62b8af0c4b251cc53049375dfed546427f (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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
 * Copyright (C) the libgit2 contributors. All rights reserved.
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */
#ifndef INCLUDE_sorted_cache_h__
#define INCLUDE_sorted_cache_h__

#include "util.h"
#include "fileops.h"
#include "vector.h"
#include "thread-utils.h"
#include "pool.h"
#include "strmap.h"

#include <stddef.h>

/*
 * The purpose of this data structure is to cache the parsed contents of a
 * file (a.k.a. the backing file) where each item in the file can be
 * identified by a key string and you want to both look them up by name
 * and traverse them in sorted order.  Each item is assumed to itself end
 * in a GIT_FLEX_ARRAY.
 */

typedef void (*git_sortedcache_free_item_fn)(void *payload, void *item);

typedef struct {
	git_refcount rc;
	git_rwlock   lock;
	size_t       item_path_offset;
	git_sortedcache_free_item_fn free_item;
	void         *free_item_payload;
	git_pool     pool;
	git_vector   items;
	git_strmap   *map;
	git_futils_filestamp stamp;
	char         path[GIT_FLEX_ARRAY];
} git_sortedcache;

/* Create a new sortedcache
 *
 * Even though every sortedcache stores items with a GIT_FLEX_ARRAY at
 * the end containing their key string, you have to provide the item_cmp
 * sorting function because the sorting function doesn't get a payload
 * and therefore can't know the offset to the item key string. :-(
 *
 * @param out The allocated git_sortedcache
 * @param item_path_offset Offset to the GIT_FLEX_ARRAY item key in the
 *        struct - use offsetof(struct mine, key-field) to get this
 * @param free_item Optional callback to free each item
 * @param free_item_payload Optional payload passed to free_item callback
 * @param item_cmp Compare the keys of two items
 * @param path The path to the backing store file for this cache; this
 *        may be NULL.  The cache makes it easy to load this and check
 *        if it has been modified since the last load and/or write.
 */
int git_sortedcache_new(
	git_sortedcache **out,
	size_t item_path_offset, /* use offsetof(struct, path-field) macro */
	git_sortedcache_free_item_fn free_item,
	void *free_item_payload,
	git_vector_cmp item_cmp,
	const char *path);

/* Copy a sorted cache
 *
 * - `copy_item` can be NULL to just use memcpy
 * - if `lock`, grabs read lock on `src` during copy and releases after
 */
int git_sortedcache_copy(
	git_sortedcache **out,
	git_sortedcache *src,
	bool lock,
	int (*copy_item)(void *payload, void *tgt_item, void *src_item),
	void *payload);

/* Free sorted cache (first calling `free_item` callbacks)
 *
 * Don't call on a locked collection - it may acquire a write lock
 */
void git_sortedcache_free(git_sortedcache *sc);

/* Increment reference count - balance with call to free */
void git_sortedcache_incref(git_sortedcache *sc);

/* Get the pathname associated with this cache at creation time */
const char *git_sortedcache_path(git_sortedcache *sc);

/*
 * CACHE WRITE FUNCTIONS
 *
 * The following functions require you to have a writer lock to make the
 * modification.  Some of the functions take a `wlock` parameter and
 * will optionally lock and unlock for you if that is passed as true.
 *
 */

/* Lock sortedcache for write */
int git_sortedcache_wlock(git_sortedcache *sc);

/* Unlock sorted cache when done with write */
void git_sortedcache_wunlock(git_sortedcache *sc);

/* Lock cache and load backing file into a buffer.
 *
 * This grabs a write lock on the cache then looks at the modification
 * time and size of the file on disk.
 *
 * If the file appears to have changed, this loads the file contents into
 * the buffer and returns a positive value leaving the cache locked - the
 * caller should parse the file content, update the cache as needed, then
 * release the lock.  NOTE: In this case, the caller MUST unlock the cache.
 *
 * If the file appears to be unchanged, then this automatically releases
 * the lock on the cache, clears the buffer, and returns 0.
 *
 * @return 0 if up-to-date, 1 if out-of-date, <0 on error
 */
int git_sortedcache_lockandload(git_sortedcache *sc, git_buf *buf);

/* Refresh file timestamp after write completes
 * You should already be holding the write lock when you call this.
 */
void git_sortedcache_updated(git_sortedcache *sc);

/* Release all items in sorted cache
 *
 * If `wlock` is true, grabs write lock and releases when done, otherwise
 * you should already be holding a write lock when you call this.
 */
int git_sortedcache_clear(git_sortedcache *sc, bool wlock);

/* Find and/or insert item, returning pointer to item data.
 * You should already be holding the write lock when you call this.
 */
int git_sortedcache_upsert(
	void **out, git_sortedcache *sc, const char *key);

/* Removes entry at pos from cache
 * You should already be holding the write lock when you call this.
 */
int git_sortedcache_remove(git_sortedcache *sc, size_t pos);

/*
 * CACHE READ FUNCTIONS
 *
 * The following functions access items in the cache.  To prevent the
 * results from being invalidated before they can be used, you should be
 * holding either a read lock or a write lock when using these functions.
 *
 */

/* Lock sortedcache for read */
int git_sortedcache_rlock(git_sortedcache *sc);

/* Unlock sorted cache when done with read */
void git_sortedcache_runlock(git_sortedcache *sc);

/* Lookup item by key - returns NULL if not found */
void *git_sortedcache_lookup(const git_sortedcache *sc, const char *key);

/* Get how many items are in the cache
 *
 * You can call this function without holding a lock, but be aware
 * that it may change before you use it.
 */
size_t git_sortedcache_entrycount(const git_sortedcache *sc);

/* Lookup item by index - returns NULL if out of range */
void *git_sortedcache_entry(git_sortedcache *sc, size_t pos);

/* Lookup index of item by key - returns GIT_ENOTFOUND if not found */
int git_sortedcache_lookup_index(
	size_t *out, git_sortedcache *sc, const char *key);

#endif