Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
spv.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
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 are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 /**
34  * @file spv.c
35  * @brief Sparse Vector API.
36  *
37  * This is a trimmed down sparse vector implementation tuned to the problem of
38  * 24-bit FC_IDs. In this case, the 24-bit index value is broken down in three
39  * 8-bit values. These values are used to index up to three 256 element arrays.
40  * Arrays are allocated, only when needed. @n @n
41  * The lookup can complete in constant time (3 indexed array references). @n @n
42  * A typical use case would be that the fabric/directory FC_IDs would cause two rows to be
43  * allocated, and the fabric assigned remote nodes would cause two rows to be allocated, with
44  * the root row always allocated. This gives five rows of 256 x sizeof(void*),
45  * resulting in 10k.
46  */
47 
48 #include "ocs_os.h"
49 #include "spv.h"
50 
51 
52 /**
53  * @ingroup spv
54  * @brief Allocate a new sparse vector row.
55  *
56  * @param os OS handle
57  * @param rowcount Count of rows.
58  *
59  * @par Description
60  * A new sparse vector row is allocated.
61  *
62  * @param rowcount Number of elements in a row.
63  *
64  * @return Returns the pointer to a row.
65  */
66 static void
67 **spv_new_row(ocs_os_handle_t os, uint32_t rowcount)
68 {
69  return ocs_malloc(os, sizeof(void*) * rowcount, OCS_M_ZERO | OCS_M_NOWAIT);
70 }
71 
72 
73 #if 0
74 /**
75  * @ingroup spv
76  * @brief Delete a sparse vector row.
77  *
78  * @par Description
79  * The resources associated with the row are freed.
80  *
81  * @param row Pointer to the row.
82  * @param rowcount Count of the elements in the row.
83  *
84  * @return None.
85  */
86 static void
87 spv_del_row(void **row, uint32_t rowcount)
88 {
89  ocs_free(row, sizeof(void*) * rowcount);
90 }
91 #endif
92 
93 
94 #if 0
95 /**
96  * @ingroup spv
97  * @brief Return maximum index for a sparse vector.
98  *
99  * @par Description
100  * The maximum index value for the sparse vector is returned.
101  *
102  * @param spv Pointer to the sparse vector object.
103  *
104  * @return Returns the maximum index value.
105  */
106 static uint32_t
107 spv_get_max_idx(sparse_vector_t spv)
108 {
109  return spv->max_idx;
110 }
111 #endif
112 
113 /**
114  * @ingroup spv
115  * @brief Delete row recursively.
116  *
117  * @par Description
118  * This function recursively deletes the rows in this sparse vector
119  *
120  * @param os OS handle
121  * @param a Pointer to the row.
122  * @param n Number of elements in the row.
123  * @param depth Depth of deleting.
124  *
125  * @return None.
126  */
127 static void
128 _spv_del(ocs_os_handle_t os, void **a, uint32_t n, uint32_t depth)
129 {
130  if (a) {
131  if (depth) {
132  uint32_t i;
133 
134  for (i = 0; i < n; i ++) {
135  _spv_del(os, a[i], n, depth-1);
136  }
137 
138  ocs_free(os, a, SPV_ROWLEN*sizeof(*a));
139  }
140  }
141 }
142 
143 /**
144  * @ingroup spv
145  * @brief Delete a sparse vector.
146  *
147  * @par Description
148  * The sparse vector is freed.
149  *
150  * @param spv Pointer to the sparse vector object.
151  */
152 void
153 spv_del(sparse_vector_t spv)
154 {
155  if (spv) {
156  _spv_del(spv->os, spv->array, SPV_ROWLEN, SPV_DIM);
157  ocs_free(spv->os, spv, sizeof(*spv));
158  }
159 }
160 
161 /**
162  * @ingroup spv
163  * @brief Instantiate a new sparse vector object.
164  *
165  * @par Description
166  * A new sparse vector is allocated.
167  *
168  * @param os OS handle
169  *
170  * @return Returns the pointer to the sparse vector, or NULL.
171  */
172 sparse_vector_t
173 spv_new(ocs_os_handle_t os)
174 {
175  sparse_vector_t spv;
176  uint32_t i;
177 
178  spv = ocs_malloc(os, sizeof(*spv), OCS_M_ZERO | OCS_M_NOWAIT);
179  if (!spv) {
180  return NULL;
181  }
182 
183  spv->os = os;
184  spv->max_idx = 1;
185  for (i = 0; i < SPV_DIM; i ++) {
186  spv->max_idx *= SPV_ROWLEN;
187  }
188 
189  return spv;
190 }
191 
192 /**
193  * @ingroup spv
194  * @brief Return the address of a cell.
195  *
196  * @par Description
197  * Returns the address of a cell, allocates sparse rows as needed if the
198  * alloc_new_rows parameter is set.
199  *
200  * @param sv Pointer to the sparse vector.
201  * @param idx Index of which to return the address.
202  * @param alloc_new_rows If TRUE, then new rows may be allocated to set values,
203  * Set to FALSE for retrieving values.
204  *
205  * @return Returns the pointer to the cell, or NULL.
206  */
207 static void
208 *spv_new_cell(sparse_vector_t sv, uint32_t idx, uint8_t alloc_new_rows)
209 {
210  uint32_t a = (idx >> 16) & 0xff;
211  uint32_t b = (idx >> 8) & 0xff;
212  uint32_t c = (idx >> 0) & 0xff;
213  void **p;
214 
215  if (idx >= sv->max_idx) {
216  return NULL;
217  }
218 
219  if (sv->array == NULL) {
220  sv->array = (alloc_new_rows ? spv_new_row(sv->os, SPV_ROWLEN) : NULL);
221  if (sv->array == NULL) {
222  return NULL;
223  }
224  }
225  p = sv->array;
226  if (p[a] == NULL) {
227  p[a] = (alloc_new_rows ? spv_new_row(sv->os, SPV_ROWLEN) : NULL);
228  if (p[a] == NULL) {
229  return NULL;
230  }
231  }
232  p = p[a];
233  if (p[b] == NULL) {
234  p[b] = (alloc_new_rows ? spv_new_row(sv->os, SPV_ROWLEN) : NULL);
235  if (p[b] == NULL) {
236  return NULL;
237  }
238  }
239  p = p[b];
240 
241  return &p[c];
242 }
243 
244 /**
245  * @ingroup spv
246  * @brief Set the sparse vector cell value.
247  *
248  * @par Description
249  * Sets the sparse vector at @c idx to @c value.
250  *
251  * @param sv Pointer to the sparse vector.
252  * @param idx Index of which to store.
253  * @param value Value to store.
254  *
255  * @return None.
256  */
257 void
258 spv_set(sparse_vector_t sv, uint32_t idx, void *value)
259 {
260  void **ref = spv_new_cell(sv, idx, TRUE);
261  if (ref) {
262  *ref = value;
263  }
264 }
265 
266 /**
267  * @ingroup spv
268  * @brief Return the sparse vector cell value.
269  *
270  * @par Description
271  * Returns the value at @c idx.
272  *
273  * @param sv Pointer to the sparse vector.
274  * @param idx Index of which to return the value.
275  *
276  * @return Returns the cell value, or NULL.
277  */
278 void
279 *spv_get(sparse_vector_t sv, uint32_t idx)
280 {
281  void **ref = spv_new_cell(sv, idx, FALSE);
282  if (ref) {
283  return *ref;
284  }
285  return NULL;
286 }
#define SPV_ROWLEN
Definition: spv.h:52
#define SPV_DIM
Definition: spv.h:53
static void _spv_del(ocs_os_handle_t os, void **a, uint32_t n, uint32_t depth)
Delete row recursively.
Definition: spv.c:128
static void ** spv_new_row(ocs_os_handle_t os, uint32_t rowcount)
Allocate a new sparse vector row.
Definition: spv.c:67
void * spv_get(sparse_vector_t sv, uint32_t idx)
Return the sparse vector cell value.
Definition: spv.c:279
static void * spv_new_cell(sparse_vector_t sv, uint32_t idx, uint8_t alloc_new_rows)
Return the address of a cell.
Definition: spv.c:208
sparse_vector_t spv_new(ocs_os_handle_t os)
Instantiate a new sparse vector object.
Definition: spv.c:173
void spv_del(sparse_vector_t spv)
Delete a sparse vector.
Definition: spv.c:153
void spv_set(sparse_vector_t sv, uint32_t idx, void *value)
Set the sparse vector cell value.
Definition: spv.c:258
Sparse Vector API.