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
RevLine 
[48e3190]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
[b1834a01]29/** @addtogroup udf
[48e3190]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>
[38d150e]41#include <stdlib.h>
[48e3190]42#include <adt/hash_table.h>
[38fc00b]43#include <adt/hash.h>
[48e3190]44#include <adt/list.h>
[3e6a98c5]45#include <stdbool.h>
[48e3190]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
[38fc00b]53typedef struct {
54 service_id_t service_id;
55 fs_index_t index;
[1b20da0]56} udf_ht_key_t;
[38fc00b]57
58static size_t udf_idx_hash(const ht_link_t *item)
[48e3190]59{
[38fc00b]60 udf_node_t *node = hash_table_get_inst(item, udf_node_t, link);
61 return hash_combine(node->instance->service_id, node->index);
[48e3190]62}
63
[5e801dc]64static size_t udf_idx_key_hash(const void *k)
[48e3190]65{
[5e801dc]66 const udf_ht_key_t *key = k;
[38fc00b]67 return hash_combine(key->service_id, key->index);
[48e3190]68}
69
[0db0df2]70static bool udf_idx_key_equal(const void *k, size_t hash, const ht_link_t *item)
[48e3190]71{
[5e801dc]72 const udf_ht_key_t *key = k;
[38fc00b]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);
[48e3190]77}
78
[61eb2ce2]79static const hash_table_ops_t udf_idx_ops = {
[48e3190]80 .hash = udf_idx_hash,
[38fc00b]81 .key_hash = udf_idx_key_hash,
82 .key_equal = udf_idx_key_equal,
83 .equal = NULL,
[1b20da0]84 .remove_callback = NULL
[48e3190]85};
86
87/** Initialization of hash table
88 *
[cde999a]89 * @return EOK on success or an error code.
[48e3190]90 *
91 */
[b7fd2a0]92errno_t udf_idx_init(void)
[48e3190]93{
[38fc00b]94 if (!hash_table_create(&udf_idx, 0, 0, &udf_idx_ops))
[48e3190]95 return ENOMEM;
[a35b458]96
[48e3190]97 return EOK;
98}
99
100/** Delete hash table
101 *
[cde999a]102 * @return EOK on success or an error code.
[48e3190]103 *
104 */
[b7fd2a0]105errno_t udf_idx_fini(void)
[48e3190]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 *
[cde999a]117 * @return EOK on success or an error code.
[48e3190]118 *
119 */
[b7fd2a0]120errno_t udf_idx_get(udf_node_t **udfn, udf_instance_t *instance, fs_index_t index)
[48e3190]121{
122 fibril_mutex_lock(&udf_idx_lock);
[38fc00b]123
124 udf_ht_key_t key = {
125 .service_id = instance->service_id,
126 .index = index
[48e3190]127 };
[a35b458]128
[38fc00b]129 ht_link_t *already_open = hash_table_find(&udf_idx, &key);
[48e3190]130 if (already_open) {
[38fc00b]131 udf_node_t *node = hash_table_get_inst(already_open,
[48e3190]132 udf_node_t, link);
133 node->ref_cnt++;
[a35b458]134
[48e3190]135 *udfn = node;
[a35b458]136
[48e3190]137 fibril_mutex_unlock(&udf_idx_lock);
138 return EOK;
139 }
[a35b458]140
[48e3190]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 *
[cde999a]151 * @return EOK on success or an error code.
[48e3190]152 *
153 */
[b7fd2a0]154errno_t udf_idx_add(udf_node_t **udfn, udf_instance_t *instance, fs_index_t index)
[48e3190]155{
156 fibril_mutex_lock(&udf_idx_lock);
[a35b458]157
[48e3190]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 }
[a35b458]163
[48e3190]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 }
[a35b458]170
[48e3190]171 fs_node_initialize(fs_node);
[a35b458]172
[48e3190]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;
[a35b458]180
[48e3190]181 fibril_mutex_initialize(&udf_node->lock);
182 fs_node->data = udf_node;
[a35b458]183
[38fc00b]184 hash_table_insert(&udf_idx, &udf_node->link);
[48e3190]185 instance->open_nodes_count++;
[a35b458]186
[48e3190]187 *udfn = udf_node;
[a35b458]188
[48e3190]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 *
[cde999a]197 * @return EOK on success or an error code.
[48e3190]198 *
199 */
[b7fd2a0]200errno_t udf_idx_del(udf_node_t *node)
[48e3190]201{
202 assert(node->ref_cnt == 0);
[a35b458]203
[48e3190]204 fibril_mutex_lock(&udf_idx_lock);
[a35b458]205
[38fc00b]206 hash_table_remove_item(&udf_idx, &node->link);
[a35b458]207
[48e3190]208 assert(node->instance->open_nodes_count > 0);
209 node->instance->open_nodes_count--;
[a35b458]210
[48e3190]211 free(node->fs_node);
212 free(node);
[a35b458]213
[48e3190]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.