objset.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. #include "slapi-plugin.h"
  42. #include "slapi-private.h"
  43. /*
  44. * The "wrapper" placed around objects in our object set.
  45. */
  46. typedef struct objset_object
  47. {
  48. Object *obj; /* pointer to actual object */
  49. struct objset_object *next; /* pointer to next object in list */
  50. } objset_object;
  51. /*
  52. * The object set itself.
  53. */
  54. typedef struct objset
  55. {
  56. objset_object *head; /* pointer to linked list of objects */
  57. objset_object *tail; /* pointer to tail of linked list */
  58. PRLock *lock; /* Lock - protects addition/deletion from list */
  59. FNFree destructor; /* Destructor callback for objset itself */
  60. } objset;
  61. /* Forward declarations */
  62. static void unlinkObjsetObjectNoLock(Objset *o, objset_object *obj_to_unlink);
  63. /*
  64. * Create a new, empty object set.
  65. * Returns a pointer to the new object set, or NULL if an error occurred.
  66. */
  67. Objset *
  68. objset_new(FNFree objset_destructor)
  69. {
  70. objset *set;
  71. set = (objset *)slapi_ch_malloc(sizeof(objset));
  72. set->lock = PR_NewLock();
  73. if (NULL == set->lock)
  74. {
  75. slapi_ch_free((void **)&set);
  76. }
  77. else
  78. {
  79. set->head = set->tail = NULL;
  80. set->destructor = objset_destructor;
  81. }
  82. return set;
  83. }
  84. /*
  85. * Delete an object set. All references to contained objects
  86. * are released, and the objset is deleted.
  87. */
  88. void
  89. objset_delete(Objset **setp)
  90. {
  91. objset_object *o, *o_next;
  92. Objset *set;
  93. PR_ASSERT(NULL != setp);
  94. set = *setp;
  95. PR_ASSERT(NULL != set);
  96. PR_Lock(set->lock);
  97. o = set->head;
  98. while (NULL != o)
  99. {
  100. o_next = o->next;
  101. object_release(o->obj); /* release our reference */
  102. slapi_ch_free((void **)&o); /* Free wrapper */
  103. o = o_next;
  104. }
  105. PR_Unlock(set->lock);
  106. PR_DestroyLock(set->lock);
  107. if (NULL != set->destructor)
  108. {
  109. set->destructor((void **)setp);
  110. }
  111. slapi_ch_free((void **)setp);
  112. }
  113. /*
  114. * Add a new object to an object set.
  115. * Return values:
  116. * OBJSET_SUCCESS: the insertion was succesful.
  117. * OBJSET_ALREADY_EXISTS: the object already exists in the set.
  118. */
  119. int
  120. objset_add_obj(Objset *set, Object *object)
  121. {
  122. objset_object *p;
  123. int exists = 0;
  124. int rc = OBJSET_SUCCESS;
  125. PR_ASSERT(NULL != set);
  126. PR_ASSERT(NULL != object);
  127. PR_Lock(set->lock);
  128. /* Make sure this object isn't already in the set */
  129. p = set->head;
  130. while (NULL != p)
  131. {
  132. if (p->obj == object)
  133. {
  134. exists = 1;
  135. break;
  136. }
  137. p = p->next;
  138. }
  139. if (exists)
  140. {
  141. rc = OBJSET_ALREADY_EXISTS;
  142. }
  143. else
  144. {
  145. objset_object *new_node = (objset_object *)slapi_ch_malloc(sizeof(objset_object));
  146. object_acquire(object); /* Record our reference */
  147. new_node->obj = object;
  148. new_node->next = NULL;
  149. if (NULL == set->head)
  150. {
  151. set->head = set->tail = new_node;
  152. }
  153. else
  154. {
  155. set->tail->next = new_node;
  156. set->tail = new_node;
  157. }
  158. }
  159. PR_Unlock(set->lock);
  160. return rc;
  161. }
  162. /*
  163. * Locate an object in an object set.
  164. *
  165. * Arguments:
  166. * set: the object set to search
  167. * compare_fn: a caller-provided function used to compare the
  168. * name against an object. This function should return
  169. * a negtive value, zero, or a positive value if the
  170. * object's name is, respectively, less that, equal
  171. * to, or greater than the provided name.
  172. * name: the name (value) to find.
  173. *
  174. * The returned object, if any, is referenced. The caller must
  175. * call object_release() when finished with the object.
  176. *
  177. * Returns the object, if found. Otherwise, returns NULL.
  178. * Implementation note: since we store objects in an unordered
  179. * linked list, all that's really important is that the compare_fn
  180. * return 0 when a match is found, and non-zero otherwise.
  181. * Other types of implementations might try to optimize the
  182. * storage, e.g. binary search.
  183. */
  184. Object *
  185. objset_find(Objset *set, CMPFn compare_fn, const void *name)
  186. {
  187. objset_object *found = NULL;
  188. PR_ASSERT(NULL != set);
  189. PR_ASSERT(NULL != name);
  190. PR_ASSERT(NULL != compare_fn);
  191. PR_Lock(set->lock);
  192. found = set->head;
  193. while (NULL != found)
  194. {
  195. if (compare_fn(found->obj, name) == 0)
  196. {
  197. break;
  198. }
  199. found = found->next;
  200. }
  201. if (NULL != found)
  202. {
  203. /* acquire object */
  204. object_acquire(found->obj);
  205. }
  206. PR_Unlock(set->lock);
  207. return found == NULL ? NULL : found->obj;
  208. }
  209. /*
  210. * Remove an object from an objset.
  211. * Returns OBJSET_SUCCESS if the object was found and removed, or
  212. * OBJSET_NO_SUCH_OBJECT if the object was not found in the list.
  213. */
  214. int
  215. objset_remove_obj(Objset *set, Object *object)
  216. {
  217. int rc = OBJSET_SUCCESS;
  218. objset_object *found;
  219. PR_ASSERT(NULL != set);
  220. PR_ASSERT(NULL != object);
  221. PR_Lock(set->lock);
  222. found = set->head;
  223. while (NULL != found)
  224. {
  225. if (found->obj == object)
  226. {
  227. break;
  228. }
  229. found = found->next;
  230. }
  231. if (NULL == found)
  232. {
  233. rc = OBJSET_NO_SUCH_OBJECT;
  234. }
  235. else
  236. {
  237. Object *saved = found->obj;
  238. /* Unlink from list */
  239. unlinkObjsetObjectNoLock(set, found);
  240. /* Release reference on object */
  241. object_release(saved);
  242. }
  243. PR_Unlock(set->lock);
  244. return rc;
  245. }
  246. /*
  247. * Prepare for iteration across an object set. Returns the first
  248. * object in the set. The returned object is referenced, therefore
  249. * the caller must either release the object, or
  250. * pass it to an objset_next_obj call, which will
  251. * implicitly release the object.
  252. * Returns the first object, or NULL if the objset contains no
  253. * objects.
  254. */
  255. Object *
  256. objset_first_obj(Objset *set)
  257. {
  258. Object *return_object;
  259. /* Be tolerant (for the replication plugin) */
  260. if (set == NULL) return NULL;
  261. PR_Lock(set->lock);
  262. if (NULL == set->head)
  263. {
  264. return_object = NULL;
  265. }
  266. else
  267. {
  268. object_acquire(set->head->obj);
  269. return_object = set->head->obj;
  270. }
  271. PR_Unlock(set->lock);
  272. return return_object;
  273. }
  274. /*
  275. * Return the next object in an object set, or NULL if there are
  276. * no more objects.
  277. * The returned object is referenced, therefore
  278. * the caller must either release the object, or
  279. * pass it to an objset_next_ob call, which will
  280. * implicitly release the object.
  281. */
  282. Object *
  283. objset_next_obj(Objset *set, Object *previous)
  284. {
  285. Object *return_object = NULL;
  286. objset_object *p;
  287. PR_ASSERT(NULL != set);
  288. PR_Lock(set->lock);
  289. /* First, find the current object */
  290. p = set->head;
  291. while (NULL != p && p->obj != previous)
  292. {
  293. p = p->next;
  294. }
  295. /* Find the next object */
  296. if (NULL != p && NULL != p->next)
  297. {
  298. return_object = p->next->obj;
  299. object_acquire(return_object);
  300. }
  301. PR_Unlock(set->lock);
  302. object_release(previous); /* Release the previous object */
  303. return return_object;
  304. }
  305. /*
  306. * Return a non-zero value if the object set is empty, or
  307. * zero if the object set is empty.
  308. */
  309. int
  310. objset_is_empty(Objset *set)
  311. {
  312. int return_value;
  313. PR_ASSERT(NULL != set);
  314. PR_Lock(set->lock);
  315. return_value = (set->head == NULL);
  316. PR_Unlock(set->lock);
  317. return return_value;
  318. }
  319. /*
  320. * Return the count of objects in the object set.
  321. */
  322. int objset_size(Objset *set)
  323. {
  324. int count = 0;
  325. objset_object *p;
  326. PR_ASSERT(NULL != set);
  327. PR_Lock(set->lock);
  328. for (p = set->head; p; p = p->next)
  329. count++;
  330. PR_Unlock(set->lock);
  331. return count;
  332. }
  333. /*
  334. * Utility function: remove object from list.
  335. * This needs to be called with the objset locked.
  336. */
  337. static void
  338. unlinkObjsetObjectNoLock(Objset *o, objset_object *obj_to_unlink)
  339. {
  340. objset_object *p = o->head;
  341. PR_ASSERT(NULL != o->head);
  342. /* Unlink from list */
  343. if (o->head == obj_to_unlink) {
  344. /* Object to unlink was at head of list */
  345. p = o->head->next;
  346. o->head = obj_to_unlink->next;
  347. } else {
  348. while (NULL != p->next && p->next != obj_to_unlink) {
  349. p = p->next;
  350. }
  351. if (NULL != p->next)
  352. {
  353. /* p points to object prior to one being removed */
  354. p->next = p->next->next;
  355. }
  356. }
  357. if (o->tail == obj_to_unlink)
  358. {
  359. o->tail = p;
  360. }
  361. /* Free the wrapper */
  362. slapi_ch_free((void **)&obj_to_unlink);
  363. }