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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
|
From a9c7fb0782e7142ae7a43385e4b166478fd40675 Mon Sep 17 00:00:00 2001
From: Justus Winter <4winter@informatik.uni-hamburg.de>
Date: Wed, 14 May 2014 16:24:21 +0200
Subject: [PATCH hurd 2/3] libihash: optimize lookup-or-insert operations
If libihash is used to implement a cache, a insertion is always
preceeded by a lookup. hurd_ihash_add has to do the lookup again.
Provide a new pair of functions, hurd_ihash_locp_add and
hurd_ihash_locp_find, that can be used in combination to avoid the
second lookup.
* libihash/ihash.c (hurd_ihash_locp_add): New function using a
location pointer...
(hurd_ihash_locp_find): ... that has been returned by this function.
* libihash/ihash.h (hurd_ihash_locp_add): New declaration.
(hurd_ihash_locp_find): Likewise.
(hurd_ihash_locp_value): New function.
---
libihash/ihash.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
libihash/ihash.h | 52 +++++++++++++++++++++++++++++++++++++
2 files changed, 129 insertions(+), 1 deletion(-)
diff --git a/libihash/ihash.c b/libihash/ihash.c
index 74e9edd..a97de3e 100644
--- a/libihash/ihash.c
+++ b/libihash/ihash.c
@@ -244,7 +244,54 @@ add_one (hurd_ihash_t ht, hurd_ihash_key_t key, hurd_ihash_value_t value)
return 0;
}
-
+
+/* Add VALUE to the hash table HT under the key KEY at LOCP. If there
+ already is an item under this key, call the cleanup function (if
+ any) for it before overriding the value. This function is faster
+ than hurd_ihash_add.
+
+ If LOCP is NULL, fall back to hurd_ihash_add. Otherwise, LOCP must
+ be valid and may either be obtained from hurd_ihash_locp_find, or
+ from an item that is currently in the hash table. If an item is
+ replaced, KEY must match the key of the previous item.
+
+ If a memory allocation error occurs, ENOMEM is returned, otherwise
+ 0. */
+error_t
+hurd_ihash_locp_add (hurd_ihash_t ht, hurd_ihash_locp_t locp,
+ hurd_ihash_key_t key, hurd_ihash_value_t value)
+{
+ struct _hurd_ihash_item *item = (struct _hurd_ihash_item *) locp;
+
+ /* In case of complications, fall back to hurd_ihash_add. */
+ if (ht->size == 0
+ || item == NULL
+ || item->value == _HURD_IHASH_DELETED
+ || hurd_ihash_get_load (ht) > ht->max_load)
+ return hurd_ihash_add (ht, key, value);
+
+ if (item->value == _HURD_IHASH_EMPTY)
+ {
+ item->key = key;
+ ht->nr_items += 1;
+ }
+ else
+ {
+ assert (item->key == key);
+ if (ht->cleanup)
+ (*ht->cleanup) (locp, ht->cleanup_data);
+ }
+
+ item->value = value;
+
+ if (ht->locp_offset != HURD_IHASH_NO_LOCP)
+ *((hurd_ihash_locp_t *) (((char *) value) + ht->locp_offset))
+ = locp;
+
+ return 0;
+}
+
+
/* Add ITEM to the hash table HT under the key KEY. If there already
is an item under this key, call the cleanup function (if any) for
it before overriding the value. If a memory allocation error
@@ -313,6 +360,35 @@ hurd_ihash_find (hurd_ihash_t ht, hurd_ihash_key_t key)
}
}
+/* Find the item in the hash table HT with key KEY. If it is found,
+ return the location of its slot in the hash table. If it is not
+ found, this function may still return a location.
+
+ This location pointer can always be safely accessed using
+ hurd_ihash_locp_value. If the lookup is successful,
+ hurd_ihash_locp_value will return the value related to KEY.
+
+ If the lookup is successful, the returned location can be used with
+ hurd_ihash_locp_add to update the item, and with
+ hurd_ihash_locp_remove to remove it.
+
+ If the lookup is not successful, the returned location can be used
+ with hurd_ihash_locp_add to add the item.
+
+ Note that returned location is only valid until the next insertion
+ or deletion. */
+hurd_ihash_locp_t
+hurd_ihash_locp_find (hurd_ihash_t ht, hurd_ihash_key_t key)
+{
+ int idx;
+
+ if (ht->size == 0)
+ return NULL;
+
+ idx = find_index (ht, key);
+ return &ht->items[idx].value;
+}
+
/* Remove the entry with the key KEY from the hash table HT. If such
an entry was found and removed, 1 is returned, otherwise 0. */
diff --git a/libihash/ihash.h b/libihash/ihash.h
index 128027a..1dbc348 100644
--- a/libihash/ihash.h
+++ b/libihash/ihash.h
@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <limits.h>
#include <stdint.h>
+#include <stddef.h>
/* The type of the values corresponding to the keys. Must be a
@@ -198,10 +199,61 @@ hurd_ihash_get_load (hurd_ihash_t ht)
error_t hurd_ihash_add (hurd_ihash_t ht, hurd_ihash_key_t key,
hurd_ihash_value_t item);
+/* Add VALUE to the hash table HT under the key KEY at LOCP. If there
+ already is an item under this key, call the cleanup function (if
+ any) for it before overriding the value. This function is faster
+ than hurd_ihash_add.
+
+ If LOCP is NULL, fall back to hurd_ihash_add. Otherwise, LOCP must
+ be valid and may either be obtained from hurd_ihash_locp_find, or
+ from an item that is currently in the hash table. If an item is
+ replaced, KEY must match the key of the previous item.
+
+ If a memory allocation error occurs, ENOMEM is returned, otherwise
+ 0. */
+error_t hurd_ihash_locp_add (hurd_ihash_t ht, hurd_ihash_locp_t locp,
+ hurd_ihash_key_t key, hurd_ihash_value_t value);
+
/* Find and return the item in the hash table HT with key KEY, or NULL
if it doesn't exist. */
hurd_ihash_value_t hurd_ihash_find (hurd_ihash_t ht, hurd_ihash_key_t key);
+/* Find the item in the hash table HT with key KEY. If it is found,
+ return the location of its slot in the hash table. If it is not
+ found, this function may still return a location.
+
+ This location pointer can always be safely accessed using
+ hurd_ihash_locp_value. If the lookup is successful,
+ hurd_ihash_locp_value will return the value related to KEY.
+
+ If the lookup is successful, the returned location can be used with
+ hurd_ihash_locp_add to update the item, and with
+ hurd_ihash_locp_remove to remove it.
+
+ If the lookup is not successful, the returned location can be used
+ with hurd_ihash_locp_add to add the item.
+
+ Note that returned location is only valid until the next insertion
+ or deletion. */
+hurd_ihash_locp_t hurd_ihash_locp_find (hurd_ihash_t ht,
+ hurd_ihash_key_t key);
+
+/* Given an hash table bucket location LOCP, return the value stored
+ there, or NULL if it is empty or LOCP is NULL. */
+static inline void *
+hurd_ihash_locp_value (hurd_ihash_locp_t locp)
+{
+ struct _hurd_ihash_item *item = (struct _hurd_ihash_item *) locp;
+
+ if (item == NULL)
+ return NULL;
+
+ if (hurd_ihash_value_valid (item->value))
+ return item->value;
+
+ return NULL;
+}
+
/* Iterate over all elements in the hash table. You use this macro
with a block, for example like this:
--
2.1.4
|