distrib.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /* --- BEGIN COPYRIGHT BLOCK ---
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * --- END COPYRIGHT BLOCK --- */
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. #include <ctype.h>
  13. #include <string.h>
  14. #include "slapi-plugin.h"
  15. /*
  16. * These are examples of distribution function as declared in mapping tree node
  17. * This function will be called for every operations
  18. * reaching this node, including subtree search operations that are started
  19. * above this node
  20. *
  21. * Parameters :
  22. * . pb is the pblock of the operation
  23. * . target_dn is the target DN of the operation
  24. * . mtn_be_names is the list of names of backends declared for this node
  25. * . be_count is the number of backends declared
  26. * . node_dn is the node where the distribution function is set
  27. *
  28. * The return value of the functions should be the indice of the backend
  29. * in the mtn_be_names table
  30. * For search operation, the value SLAPI_BE_ALL_BACKENDS can be used to
  31. * specify that all backends must be searched
  32. * The use of value SLAPI_BE_ALL_BACKENDS for operation other than search
  33. * is not supported and may give random results
  34. *
  35. */
  36. /*
  37. * Distribute the entries based on the first letter of their rdn
  38. *
  39. * . Entries starting with anything other that a-z or A-Z will always
  40. * go in backend 0
  41. * . Entries starting with letter (a-z or A-Z) will be shared between
  42. * the backends depending following the alphabetic order
  43. * Example : if 3 backends are used, entries starting with A-I will go
  44. * in backend 0, entries starting with J-R will go in backend 1, entries
  45. * starting with S-Z will go in backend 2
  46. *
  47. * Of course this won't work for all locales...
  48. *
  49. * This example only works for a flat namespace below the node DN
  50. */
  51. int alpha_distribution(Slapi_PBlock *pb, Slapi_DN * target_dn,
  52. char **mtn_be_names, int be_count, Slapi_DN * node_dn)
  53. {
  54. unsigned long op_type;
  55. Slapi_Operation *op;
  56. char *rdn_type;
  57. char *rdn_value;
  58. Slapi_RDN *rdn = NULL;
  59. char c;
  60. /* first check the operation type
  61. * searches at node level or above it should go in all backends
  62. * searches below node level should go in only one backend
  63. */
  64. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  65. op_type = slapi_op_get_type(op);
  66. if ((op_type == SLAPI_OPERATION_SEARCH) &&
  67. slapi_sdn_issuffix(node_dn, target_dn))
  68. return SLAPI_BE_ALL_BACKENDS;
  69. /* now choose the backend
  70. * anything starting with a char different from a-z or A-Z will
  71. * go in backend 0
  72. */
  73. /* get the first char of first value of rdn */
  74. rdn = slapi_rdn_new();
  75. slapi_sdn_get_rdn(target_dn, rdn);
  76. slapi_rdn_get_first(rdn, &rdn_type, &rdn_value);
  77. c = rdn_value[0];
  78. slapi_rdn_free(&rdn);
  79. if (!(((c >= 'a') && (c <= 'z')) ||
  80. ((c >= 'A') && (c <= 'Z')) ))
  81. {
  82. return 0;
  83. }
  84. /* for entries with rdn starting with alphabetic characters
  85. * use the formula : (c - 'A') * be_count/26
  86. * to calculate the backend number
  87. */
  88. return (toupper(c) - 'A') * be_count/26;
  89. }
  90. /*
  91. * Distribute the entries based on a simple hash algorithme
  92. */
  93. int hash_distribution(Slapi_PBlock *pb, Slapi_DN * target_dn,
  94. char **mtn_be_names, int be_count, Slapi_DN * node_dn)
  95. {
  96. unsigned long op_type;
  97. Slapi_Operation *op;
  98. char *rdn_type;
  99. char *rdn_value;
  100. Slapi_RDN *rdn = NULL;
  101. int hash_value;
  102. /* first check the operation type
  103. * searches at node level or above it should go in all backends
  104. * searches below node level should go in only one backend
  105. */
  106. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  107. op_type = slapi_op_get_type(op);
  108. if ((op_type == SLAPI_OPERATION_SEARCH) &&
  109. slapi_sdn_issuffix(node_dn, target_dn))
  110. return SLAPI_BE_ALL_BACKENDS;
  111. /* now choose the backend
  112. */
  113. /* get the rdn and hash it to compute the backend number
  114. * use a simple hash for this example
  115. */
  116. rdn = slapi_rdn_new();
  117. slapi_sdn_get_rdn(target_dn, rdn);
  118. slapi_rdn_get_first(rdn, &rdn_type, &rdn_value);
  119. /* compute the hash value */
  120. hash_value = 0;
  121. while (*rdn_value)
  122. {
  123. hash_value += *rdn_value;
  124. rdn_value++;
  125. }
  126. hash_value = hash_value % be_count;
  127. slapi_rdn_free(&rdn);
  128. /* use the hash_value as the returned backend number */
  129. return hash_value;
  130. }
  131. /*
  132. * This plugin allows to use a local backend in conjonction with
  133. * a chaining backend
  134. * The ldbm backend is considered a read-only replica of the data
  135. * The chaining backend point to a red-write replica of the data
  136. * This distribution logic forward the update request to the chaining
  137. * backend, and send the search request to the local dbm database
  138. *
  139. * The mechanism for updating the local read-only replica is not
  140. * taken into account by this plugin
  141. *
  142. * To be able to use it one must define one ldbm backend and one chaining
  143. * backend in the mapping tree node
  144. *
  145. */
  146. int chaining_distribution(Slapi_PBlock *pb, Slapi_DN * target_dn,
  147. char **mtn_be_names, int be_count, Slapi_DN * node_dn)
  148. {
  149. char * requestor_dn;
  150. unsigned long op_type;
  151. Slapi_Operation *op;
  152. int repl_op = 0;
  153. int local_backend = -1;
  154. int chaining_backend = -1;
  155. int i;
  156. char * name;
  157. /* first, we have to decide which backend is the local backend
  158. * and which is the chaining one
  159. * For the purpose of this example use the backend name :
  160. * the backend with name starting with ldbm is local
  161. * the bakend with name starting with chaining is remote
  162. */
  163. local_backend = -1;
  164. chaining_backend = -1;
  165. for (i=0; i<be_count; i++)
  166. {
  167. name = mtn_be_names[i];
  168. if ((0 == strncmp(name, "ldbm", 4)) ||
  169. (0 == strncmp(name, "user", 4)))
  170. local_backend = i;
  171. else if (0 == strncmp(name, "chaining", 8))
  172. chaining_backend = i;
  173. }
  174. /* Check the operation type
  175. * read-only operation will go to the local backend
  176. * updates operation will go to the chaining backend
  177. */
  178. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  179. op_type = slapi_op_get_type(op);
  180. if ((op_type == SLAPI_OPERATION_SEARCH) ||
  181. (op_type == SLAPI_OPERATION_BIND) ||
  182. (op_type == SLAPI_OPERATION_UNBIND) ||
  183. (op_type == SLAPI_OPERATION_COMPARE))
  184. return local_backend;
  185. /* if the operation is done by directory manager
  186. * use local database even for updates because it is an administrative
  187. * operation
  188. * remarks : one could also use an update DN in the same way
  189. * to let update operation go to the local backend when they are done
  190. * by specific administrator user but let all the other user
  191. * go to the read-write replica
  192. */
  193. slapi_pblock_get( pb, SLAPI_REQUESTOR_DN, &requestor_dn );
  194. if (slapi_dn_isroot(requestor_dn))
  195. return local_backend;
  196. /* if the operation is a replicated operation
  197. * use local database even for updates to avoid infinite loops
  198. */
  199. slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
  200. if (repl_op)
  201. return local_backend;
  202. /* all other case (update while not directory manager) :
  203. * use the chaining backend
  204. */
  205. return chaining_backend;
  206. }