source: mainline/uspace/srv/fs/udf/udf_idx.c

Last change on this file was 0db0df2, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 months ago

Hash table improvements

Implement hash_table_foreach macro, analogous to list_foreach.

Remove superfluous argument to hash_table_find_next().
(If the user needs to recheck the part of the list already
checked by hash_table_find(), they can just rerun that function.)

Add hash argument to hash_table_ops_t::key_equal.
The big change here is that users with big keys can store the hash
value alongside key in their entries, and for the low low cost of
sizeof(size_t) bytes eliminate a bunch of expensive key comparisons.

Also added a hash function for strings and arbitrary data.
Found this one by asking ChatGPT, because the latency of accesses
to my book collection is currently a couple of hours.

+ Some drive-by unused #include removal.

  • Property mode set to 100644
File size: 5.2 KB
Line 
1/*
2 * Copyright (c) 2012 Julia Medvedeva
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup udf
30 * @{
31 */
32/**
33 * @file udf_idx.c
34 * @brief Very simple UDF hashtable for nodes
35 */
36
37#include <errno.h>
38#include <str.h>
39#include <assert.h>
40#include <fibril_synch.h>
41#include <stdlib.h>
42#include <adt/hash_table.h>
43#include <adt/hash.h>
44#include <adt/list.h>
45#include <stdbool.h>
46#include "udf_idx.h"
47#include "udf.h"
48
49static FIBRIL_MUTEX_INITIALIZE(udf_idx_lock);
50
51static hash_table_t udf_idx;
52
53typedef struct {
54 service_id_t service_id;
55 fs_index_t index;
56} udf_ht_key_t;
57
58static size_t udf_idx_hash(const ht_link_t *item)
59{
60 udf_node_t *node = hash_table_get_inst(item, udf_node_t, link);
61 return hash_combine(node->instance->service_id, node->index);
62}
63
64static size_t udf_idx_key_hash(const void *k)
65{
66 const udf_ht_key_t *key = k;
67 return hash_combine(key->service_id, key->index);
68}
69
70static bool udf_idx_key_equal(const void *k, size_t hash, const ht_link_t *item)
71{
72 const udf_ht_key_t *key = k;
73 udf_node_t *node = hash_table_get_inst(item, udf_node_t, link);
74
75 return (key->service_id == node->instance->service_id) &&
76 (key->index == node->index);
77}
78
79static const hash_table_ops_t udf_idx_ops = {
80 .hash = udf_idx_hash,
81 .key_hash = udf_idx_key_hash,
82 .key_equal = udf_idx_key_equal,
83 .equal = NULL,
84 .remove_callback = NULL
85};
86
87/** Initialization of hash table
88 *
89 * @return EOK on success or an error code.
90 *
91 */
92errno_t udf_idx_init(void)
93{
94 if (!hash_table_create(&udf_idx, 0, 0, &udf_idx_ops))
95 return ENOMEM;
96
97 return EOK;
98}
99
100/** Delete hash table
101 *
102 * @return EOK on success or an error code.
103 *
104 */
105errno_t udf_idx_fini(void)
106{
107 hash_table_destroy(&udf_idx);
108 return EOK;
109}
110
111/** Get node from hash table
112 *
113 * @param udfn Returned value - UDF node
114 * @param instance UDF instance
115 * @param index Absolute position of ICB (sector)
116 *
117 * @return EOK on success or an error code.
118 *
119 */
120errno_t udf_idx_get(udf_node_t **udfn, udf_instance_t *instance, fs_index_t index)
121{
122 fibril_mutex_lock(&udf_idx_lock);
123
124 udf_ht_key_t key = {
125 .service_id = instance->service_id,
126 .index = index
127 };
128
129 ht_link_t *already_open = hash_table_find(&udf_idx, &key);
130 if (already_open) {
131 udf_node_t *node = hash_table_get_inst(already_open,
132 udf_node_t, link);
133 node->ref_cnt++;
134
135 *udfn = node;
136
137 fibril_mutex_unlock(&udf_idx_lock);
138 return EOK;
139 }
140
141 fibril_mutex_unlock(&udf_idx_lock);
142 return ENOENT;
143}
144
145/** Create new node in hash table
146 *
147 * @param udfn Returned value - new UDF node
148 * @param instance UDF instance
149 * @param index Absolute position of ICB (sector)
150 *
151 * @return EOK on success or an error code.
152 *
153 */
154errno_t udf_idx_add(udf_node_t **udfn, udf_instance_t *instance, fs_index_t index)
155{
156 fibril_mutex_lock(&udf_idx_lock);
157
158 udf_node_t *udf_node = malloc(sizeof(udf_node_t));
159 if (udf_node == NULL) {
160 fibril_mutex_unlock(&udf_idx_lock);
161 return ENOMEM;
162 }
163
164 fs_node_t *fs_node = malloc(sizeof(fs_node_t));
165 if (fs_node == NULL) {
166 free(udf_node);
167 fibril_mutex_unlock(&udf_idx_lock);
168 return ENOMEM;
169 }
170
171 fs_node_initialize(fs_node);
172
173 udf_node->index = index;
174 udf_node->instance = instance;
175 udf_node->ref_cnt = 1;
176 udf_node->link_cnt = 0;
177 udf_node->fs_node = fs_node;
178 udf_node->data = NULL;
179 udf_node->allocators = NULL;
180
181 fibril_mutex_initialize(&udf_node->lock);
182 fs_node->data = udf_node;
183
184 hash_table_insert(&udf_idx, &udf_node->link);
185 instance->open_nodes_count++;
186
187 *udfn = udf_node;
188
189 fibril_mutex_unlock(&udf_idx_lock);
190 return EOK;
191}
192
193/** Delete node from hash table
194 *
195 * @param node UDF node
196 *
197 * @return EOK on success or an error code.
198 *
199 */
200errno_t udf_idx_del(udf_node_t *node)
201{
202 assert(node->ref_cnt == 0);
203
204 fibril_mutex_lock(&udf_idx_lock);
205
206 hash_table_remove_item(&udf_idx, &node->link);
207
208 assert(node->instance->open_nodes_count > 0);
209 node->instance->open_nodes_count--;
210
211 free(node->fs_node);
212 free(node);
213
214 fibril_mutex_unlock(&udf_idx_lock);
215 return EOK;
216}
217
218/**
219 * @}
220 */
Note: See TracBrowser for help on using the repository browser.