| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- /* --- BEGIN COPYRIGHT BLOCK ---
- * This Program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; version 2 of the License.
- *
- * This Program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * In addition, as a special exception, Red Hat, Inc. gives You the additional
- * right to link the code of this Program with code not covered under the GNU
- * General Public License ("Non-GPL Code") and to distribute linked combinations
- * including the two, subject to the limitations in this paragraph. Non-GPL Code
- * permitted under this exception must only link to the code of this Program
- * through those well defined interfaces identified in the file named EXCEPTION
- * found in the source code files (the "Approved Interfaces"). The files of
- * Non-GPL Code may instantiate templates or use macros or inline functions from
- * the Approved Interfaces without causing the resulting work to be covered by
- * the GNU General Public License. Only Red Hat, Inc. may make changes or
- * additions to the list of Approved Interfaces. You must obey the GNU General
- * Public License in all respects for all of the Program code and other code used
- * in conjunction with the Program except the Non-GPL Code covered by this
- * exception. If you modify this file, you may extend this exception to your
- * version of the file, but you are not obligated to do so. If you do not wish to
- * provide this exception without modification, you must delete this exception
- * statement from your version and license this file solely under the GPL without
- * exception.
- *
- *
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- * --- END COPYRIGHT BLOCK --- */
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- #include <ctype.h>
- #include <string.h>
- #include "slapi-plugin.h"
- /*
- * These are examples of distribution function as declared in mapping tree node
- * This function will be called for every operations
- * reaching this node, including subtree search operations that are started
- * above this node
- *
- * Parameters :
- * . pb is the pblock of the operation
- * . target_dn is the target DN of the operation
- * . mtn_be_names is the list of names of backends declared for this node
- * . be_count is the number of backends declared
- * . node_dn is the node where the distribution function is set
- *
- * The return value of the functions should be the indice of the backend
- * in the mtn_be_names table
- * For search operation, the value SLAPI_BE_ALL_BACKENDS can be used to
- * specify that all backends must be searched
- * The use of value SLAPI_BE_ALL_BACKENDS for operation other than search
- * is not supported and may give random results
- *
- */
- /*
- * Distribute the entries based on the first letter of their rdn
- *
- * . Entries starting with anything other that a-z or A-Z will always
- * go in backend 0
- * . Entries starting with letter (a-z or A-Z) will be shared between
- * the backends depending following the alphabetic order
- * Example : if 3 backends are used, entries starting with A-I will go
- * in backend 0, entries starting with J-R will go in backend 1, entries
- * starting with S-Z will go in backend 2
- *
- * Of course this won't work for all locales...
- *
- * This example only works for a flat namespace below the node DN
- */
- int alpha_distribution(Slapi_PBlock *pb, Slapi_DN * target_dn,
- char **mtn_be_names, int be_count, Slapi_DN * node_dn)
- {
- unsigned long op_type;
- Slapi_Operation *op;
- char *rdn_type;
- char *rdn_value;
- Slapi_RDN *rdn = NULL;
- char c;
- /* first check the operation type
- * searches at node level or above it should go in all backends
- * searches below node level should go in only one backend
- */
- slapi_pblock_get(pb, SLAPI_OPERATION, &op);
- op_type = slapi_op_get_type(op);
- if ((op_type == SLAPI_OPERATION_SEARCH) &&
- slapi_sdn_issuffix(node_dn, target_dn))
- return SLAPI_BE_ALL_BACKENDS;
- /* now choose the backend
- * anything starting with a char different from a-z or A-Z will
- * go in backend 0
- */
- /* get the first char of first value of rdn */
- rdn = slapi_rdn_new();
- slapi_sdn_get_rdn(target_dn, rdn);
- slapi_rdn_get_first(rdn, &rdn_type, &rdn_value);
- c = rdn_value[0];
- slapi_rdn_free(&rdn);
-
- if (!(((c >= 'a') && (c <= 'z')) ||
- ((c >= 'A') && (c <= 'Z')) ))
- {
- return 0;
- }
- /* for entries with rdn starting with alphabetic characters
- * use the formula : (c - 'A') * be_count/26
- * to calculate the backend number
- */
- return (toupper(c) - 'A') * be_count/26;
- }
- /*
- * Distribute the entries based on a simple hash algorithme
- */
- int hash_distribution(Slapi_PBlock *pb, Slapi_DN * target_dn,
- char **mtn_be_names, int be_count, Slapi_DN * node_dn)
- {
- unsigned long op_type;
- Slapi_Operation *op;
- char *rdn_type;
- char *rdn_value;
- Slapi_RDN *rdn = NULL;
- int hash_value;
- /* first check the operation type
- * searches at node level or above it should go in all backends
- * searches below node level should go in only one backend
- */
- slapi_pblock_get(pb, SLAPI_OPERATION, &op);
- op_type = slapi_op_get_type(op);
- if ((op_type == SLAPI_OPERATION_SEARCH) &&
- slapi_sdn_issuffix(node_dn, target_dn))
- return SLAPI_BE_ALL_BACKENDS;
- /* now choose the backend
- */
- /* get the rdn and hash it to compute the backend number
- * use a simple hash for this example
- */
- rdn = slapi_rdn_new();
- slapi_sdn_get_rdn(target_dn, rdn);
- slapi_rdn_get_first(rdn, &rdn_type, &rdn_value);
- /* compute the hash value */
- hash_value = 0;
- while (*rdn_value)
- {
- hash_value += *rdn_value;
- rdn_value++;
- }
- hash_value = hash_value % be_count;
- slapi_rdn_free(&rdn);
- /* use the hash_value as the returned backend number */
- return hash_value;
- }
- /*
- * This plugin allows to use a local backend in conjonction with
- * a chaining backend
- * The ldbm backend is considered a read-only replica of the data
- * The chaining backend point to a red-write replica of the data
- * This distribution logic forward the update request to the chaining
- * backend, and send the search request to the local dbm database
- *
- * The mechanism for updating the local read-only replica is not
- * taken into account by this plugin
- *
- * To be able to use it one must define one ldbm backend and one chaining
- * backend in the mapping tree node
- *
- */
- int chaining_distribution(Slapi_PBlock *pb, Slapi_DN * target_dn,
- char **mtn_be_names, int be_count, Slapi_DN * node_dn)
- {
- char * requestor_dn;
- unsigned long op_type;
- Slapi_Operation *op;
- int repl_op = 0;
- int local_backend = -1;
- int chaining_backend = -1;
- int i;
- char * name;
- /* first, we have to decide which backend is the local backend
- * and which is the chaining one
- * For the purpose of this example use the backend name :
- * the backend with name starting with ldbm is local
- * the bakend with name starting with chaining is remote
- */
- local_backend = -1;
- chaining_backend = -1;
- for (i=0; i<be_count; i++)
- {
- name = mtn_be_names[i];
- if ((0 == strncmp(name, "ldbm", 4)) ||
- (0 == strncmp(name, "user", 4)))
- local_backend = i;
- else if (0 == strncmp(name, "chaining", 8))
- chaining_backend = i;
- }
- /* Check the operation type
- * read-only operation will go to the local backend
- * updates operation will go to the chaining backend
- */
- slapi_pblock_get(pb, SLAPI_OPERATION, &op);
- op_type = slapi_op_get_type(op);
- if ((op_type == SLAPI_OPERATION_SEARCH) ||
- (op_type == SLAPI_OPERATION_BIND) ||
- (op_type == SLAPI_OPERATION_UNBIND) ||
- (op_type == SLAPI_OPERATION_COMPARE))
- return local_backend;
- /* if the operation is done by directory manager
- * use local database even for updates because it is an administrative
- * operation
- * remarks : one could also use an update DN in the same way
- * to let update operation go to the local backend when they are done
- * by specific administrator user but let all the other user
- * go to the read-write replica
- */
- slapi_pblock_get( pb, SLAPI_REQUESTOR_DN, &requestor_dn );
- if (slapi_dn_isroot(requestor_dn))
- return local_backend;
- /* if the operation is a replicated operation
- * use local database even for updates to avoid infinite loops
- */
- slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
- if (repl_op)
- return local_backend;
- /* all other case (update while not directory manager) :
- * use the chaining backend
- */
- return chaining_backend;
- }
|