/cvs/cluster/cluster/rgmanager/event-script.txt,v --> standard output
revision 1.1
--- cluster/rgmanager/event-script.txt
+++ - 2007-11-30 21:36:29.524613000 +0000
@@ -0,0 +1,305 @@
+TODO:
+* Return correct error codes to clusvcadm (currently it always returns
+ "Unknown")
+* Write glue for 'migrate' operations and migrate-enabled services
+
+Basic configuration specification:
+
+ <rm>
+ <events>
+ <event class="node"/> <!-- all node events -->
+ <event class="node"
+ node="bar"/> <!-- events concerning 'bar' -->
+ <event class="node"
+ node="foo"
+ node_state="up"/> <!-- 'up' events for 'foo' -->
+ <event class="node"
+ node_id="3"
+ node_state="down"/> <!-- 'down' events for node ID 3 -->
+
+ (note, all service ops and such deal with node ID, not
+ with node names)
+
+ <event class="service"/> <!-- all service events-->
+ <event class="service"
+ service_name="A"/> <!-- events concerning 'A' -->
+ <event class="service"
+ service_name="B"
+ service_state="started"/> <!-- when 'B' is started... -->
+ <event class="service"
+ service_name="B"
+ service_state="started"/>
+ service_owner="3"/> <!-- when 'B' is started on node 3... -->
+
+ <event class="service"
+ priority="1"
+ service_state="started"/>
+ service_owner="3"/> <!-- when 'B' is started on node 3, do this
+ before the other event handlers ... -->
+
+
+ </events>
+ ...
+ </rm>
+
+General globals available from all scripts:
+
+ node_self - local node ID
+ event_type - event class, either:
+ EVENT_NONE - unspecified / unknown
+ EVENT_NODE - node transition
+ EVENT_SERVICE - service transition
+ EVENT_USER - a user-generated request
+ EVENT_CONFIG - [NOT CONFIGURABLE]
+
+Node event globals (i.e. when event_type == EVENT_NODE):
+
+ node_id - node ID which is transitioning
+ node_name - name of node which is transitioning
+ node_state - new node state (NODE_ONLINE or NODE_OFFLINE, or if you prefer,
+ 1 or 0, respectively)
+ node_clean - 0 if the node has not been fenced, 1 if the node has been
+ fenced
+
+Service event globals (i.e. when event_type == EVENT_SERVICE):
+
+ service_name - Name of service which transitioned
+ service_state - new state of service
+ service_owner - new owner of service (or <0 if service is no longer
+ running)
+ service_last_owner - Last owner of service if known. Used for when
+ service_state = "recovering" generally, in order to
+ apply restart/relocate/disable policy.
+
+User event globals (i.e. when event_type == EVENT_USER):
+
+ service_name - service to perform request upon
+ user_request - request to perform (USER_ENABLE, USER_DISABLE,
+ USER_STOP, USER_RELOCATE, [TODO] USER_MIGRATE)
+ user_target - target node ID if applicable
+
+
+Scripting functions - Informational:
+
+ node_list = nodes_online();
+
+ Returns a list of all online nodes.
+
+ service_list = service_list();
+
+ Returns a list of all configured services.
+
+ (restarts, last_owner, owner, state) = service_status(service_name);
+
+ Returns the state, owner, last_owner, and restarts. Note that
+ all return values are optional, but are right-justified per S-Lang
+ specification. This means if you only want the 'state', you can use:
+
+ (state) = service_status(service_name);
+
+ However, if you need the restart count, you must provide all four
+ return values as above.
+
+ (nofailback, restricted, ordered, node_list) =
+ service_domain_info(service_name);
+
+ Returns the failover domain specification, if it exists, for the
+ specified service name. The node list returned is an ordered list
+ according to priority levels. In the case of unordered domains,
+ the ordering of the returned list is pseudo-random.
+
+Scripting functions - Operational:
+
+ err = service_start(service_name, node_list, [avoid_list]);
+
+ Start a non-running, (but runnable, i.e. not failed)
+ service on the first node in node_list. Failing that, start it on
+ the second node in node_list and so forth. One may also specify
+ an avoid list, but it's better to just use the subtract() function
+ below.
+
+ err = service_stop(service_name, [0 = stop, 1 = disable]);
+
+ Stop a running service. The second parameter is optional, and if
+ non-zero is specified, the service will enter the disabled state.
+
+ ... stuff that's not done but needs to be:
+
+ err = service_relocate(service_name, node_list);
+
+ Move a running service to the specified node_list in order of
+ preference. In the case of VMs, this is actually a migrate-or-
+ relocate operation.
+
+Utility functions - Node list manipulation
+
+ node_list = union(left_node_list, right_node_list);
+
+ Calculates the union between the two node list, removing duplicates
+ and preserving ordering according to left_node_list. Any added
+ values from right_node_list will appear in their order, but
+ after left_node_list in the returned list.
+
+ node_list = intersection(left_node_list, right_node_list);
+
+ Calculates the intersection (items in both lists) between the two
+ node lists, removing duplicates and preserving ordering according
+ to left_node_list. Any added values from right_node_list will
+ appear in their order, but after left_node_list in the returned list.
+
+ node_list = delta(left_node_list, right_node_list);
+
+ Calculates the delta (items not in both lists) between the two
+ node lists, removing duplicates and preserving ordering according
+ to left_node_list. Any added values from right_node_list will
+ appear in their order, but after left_node_list in the returned list.
+
+ node_list = subtract(left_node_list, right_node_list);
+
+ Removes any duplicates as well as items specified in right_node_list
+ from left_node_list. Example:
+
+ all_nodes = nodes_online();
+ allowed_nodes = subtract(nodes_online, node_to_avoid);
+
+Utility functions - Logging:
+
+ debug(item1, item2, ...); LOG_DEBUG level
+ info(...); LOG_INFO level
+ notice(...); LOG_NOTICE level
+ warning(...); LOG_WARNING level
+ err(...); LOG_ERR level
+ crit(...); LOG_CRIT level
+ alert(...); LOG_ALERT level
+ emerg(...); LOG_EMERG level
+
+ items - These can be strings, integer lists, or integers. Logging
+ string lists is not supported.
+
+ level - the level is consistent with syslog(8)
+
+ stop_processing();
+
+ Calling this function will prevent further event scripts from being
+ executed on a particular event. Call this script if, for example,
+ you do not wish for the default event handler to process the event.
+
+ Note: This does NOT terminate the caller script; that is, the
+ script being executed will run to completion.
+
+Event scripts are written in a language called S-Lang; documentation specifics
+about the language are available at http://www.s-lang.org
+
+Example script (creating a follows-but-avoid-after-start behavior):
+%
+% If the main queue server and replication queue server are on the same
+% node, relocate the replication server somewhere else if possible.
+%
+define my_sap_event_trigger()
+{
+ variable state, owner_rep, owner_main;
+ variable nodes, allowed;
+
+ %
+ % If this was a service event, don't execute the default event
+ % script trigger after this script completes.
+ %
+ if (event_type == EVENT_SERVICE) {
+ stop_processing();
+ }
+
+ (owner_main, state) = service_status("service:main_queue");
+ (owner_rep, state) = service_status("service:replication_server");
+
+ if ((event_type == EVENT_NODE) and (owner_main == node_id) and
+ (node_state == NODE_OFFLINE) and (owner_rep >= 0)) {
+ %
+ % uh oh, the owner of the main server died. Restart it
+ % on the node running the replication server
+ %
+ notice("Starting Main Queue Server on node ", owner_rep);
+ ()=service_start("service:main_queue", owner_rep);
+ return;
+ }
+
+ %
+ % S-Lang doesn't short-circuit prior to 2.1.0
+ %
+ if ((owner_main >= 0) and
+ ((owner_main == owner_rep) or (owner_rep < 0))) {
+
+ %
+ % Get all online nodes
+ %
+ nodes = nodes_online();
+
+ %
+ % Drop out the owner of the main server
+ %
+ allowed = subtract(nodes, owner_main);
+ if ((owner_rep >= 0) and (length(allowed) == 0)) {
+ %
+ % Only one node is online and the rep server is
+ % already running. Don't do anything else.
+ %
+ return;
+ }
+
+ if ((length(allowed) == 0) and (owner_rep < 0)) {
+ %
+ % Only node online is the owner ... go ahead
+ % and start it, even though it doesn't increase
+ % availability to do so.
+ %
+ allowed = owner_main;
+ }
+
+ %
+ % Move the replication server off the node that is
+ % running the main server if a node's available.
+ %
+ if (owner_rep >= 0) {
+ ()=service_stop("service:replication_server");
+ }
+ ()=service_start("service:replication_server", allowed);
+ }
+
+ return;
+}
+
+my_sap_event_trigger();
+
+
+Relevant <rm> section from cluster.conf:
+
+ <rm central_processing="1">
+ <events>
+ <event name="main-start" class="service"
+ service="service:main_queue"
+ service_state="started"
+ file="/tmp/sap.sl"/>
+ <event name="rep-start" class="service"
+ service="service:replication_server"
+ service_state="started"
+ file="/tmp/sap.sl"/>
+ <event name="node-up" node_state="up"
+ class="node"
+ file="/tmp/sap.sl"/>
+
+ </events>
+ <failoverdomains>
+ <failoverdomain name="all" ordered="1" restricted="1">
+ <failoverdomainnode name="molly"
+priority="2"/>
+ <failoverdomainnode name="frederick"
+priority="1"/>
+ </failoverdomain>
+ </failoverdomains>
+ <resources/>
+ <service name="main_queue"/>
+ <service name="replication_server" autostart="0"/>
+ <!-- replication server is started when main-server start
+ event completes -->
+ </rm>
+
+
--- cluster/rgmanager/ChangeLog 2007/11/30 20:36:17 1.61
+++ cluster/rgmanager/ChangeLog 2007/11/30 21:36:28 1.62
@@ -1,8 +1,58 @@
2007-11-30 Lon Hohberger <lhh at redhat.com>
- * src/resources/*: Merge misc. updates from RHEL5 branch.
- * src/utils/*: Merge misc. updates from RHEL5 branch.
- * include/*.h, src/daemons/*: Merge status-counter patch
- from RHEL5 branch.
+ * Commit RIND / S-Lang script engine [untested]
+
+[RHEL5 merged ChangeLog Entries]
+2007-11-30 Lon Hohberger <lhh at redhat.com>
+ * src/resources/clusterfs.sh: Retry mount up to 3 times to avoid
+ race condition during another process mounting a GFS volume
+ * src/resources/vm.sh, service.sh: Add defaults for values.
+ Make vm.sh work with more service attrs (max restarts)
+ * src/utils/clustat.c: Make output of clustat terminal-width
+ dependent
+
+2007-11-26 Lon Hohberger <lhh at redhat.com>
+ * include/reslist.h: Add restart counters to resource node structure
+ (intended for top-level resources, i.e. services, vms...)
+ * include/restart_counter.h: Add header file for restart counter
+ * src/daemons/Makefile: Fix build to include restart counters
+ * src/daemons/restart_counter.c: Implement restart counters #247139
+ * src/daemons/fo_domain.c, groups.c, restart_counter.c, resrules.c,
+ restree.c, test.c: Glue for restart counters.
+ * src/daemons/reslist.c: Glue for restart counters. Make expand_time
+ parser more robust to allow things like '1h30m' as a time value.
+ * src/daemons/main.c: Mark quorum disk offline in the correct
+ place to avoid extraneous log messages
+ * src/daemons/rg_state.c: Allow marking service as stopped if
+ stuck in recover state. Make service which failed to start
+ go to stopped state. Glue for restart counters.
+ * src/resources/service.sh, vm.sh: Add parameters for restart
+ counters #247139
+
+2007-11-14 Lon Hohberger <lhh at redhat.com>
+ * src/utils/clulog.c: Make clulog honor rgmanager log levels
+ (#289501)
+ * src/clulib/vft.c: Fix #303981 - crash on rgmanager restart in some
+ cases
+ * man/clusvcadm.8: Remove references to clushutdown from man page;
+ resolves #324151
+ * src/resources/netfs.sh: Apply patch from Marco Ceci to fix #358161
+ * src/resources/vm.sh: Make default migration policy live instead
+ of pause for Xen virtual machines. Also make it configurable instead
+ of static. Resolves #345871
+
+2007-11-13 Lon Hohberger <lhh at redhat.com>
+ * src/resources/clusterfs.sh: Add support for self_fence operation
+ to clusterfs resource agent
+ * src/resources/service.sh: Add default values to service.sh
+
+2007-10-26 Lon Hohberger <lhh at redhat.com>
+ * src/daemons/main.c, src/utils/clustat.c, clusvcadm.c:
+ Fix #354391
+
+2007-09-25 Lon Hohberger <lhh at redhat.com>
+ * src/daemons/restree.c: Apply patch to fix side case re: 229650
+ Patch from Simone Gotti. Resolves: #229650
+[End RHEL5 merged changes]
2007-08-30 Lon Hohberger <lhh at redhat.com>
* src/daemons/restree.c, rg_state.c: Fix tree-restart bug
--- cluster/rgmanager/TODO 2006/07/19 18:43:32 1.8
+++ cluster/rgmanager/TODO 2007/11/30 21:36:28 1.9
@@ -1,5 +0,0 @@
-* Make live-migration of resources work; preferrably so that admins
-can manually migrate Xen VMs to other nodes without telling the cluster
-about it. That is, the cluster should be able to acquire running VMs
-and update its state accordingly.
-* Test against a working Xen build and shake out bugs
/cvs/cluster/cluster/rgmanager/include/event.h,v --> standard output
revision 1.1
--- cluster/rgmanager/include/event.h
+++ - 2007-11-30 21:36:29.926075000 +0000
@@ -0,0 +1,145 @@
+/*
+ Copyright Red Hat, Inc. 2007
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 as published
+ by the Free Software Foundation.
+
+ 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; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
+ MA 02139, USA.
+*/
+#ifndef _EVENT_H
+#define _EVENT_H
+
+/* 128 is a bit big, but it should be okay */
+typedef struct __rge_q {
+ char rg_name[128];
+ uint32_t rg_state;
+ uint32_t pad1;
+ int rg_owner;
+ int rg_last_owner;
+} group_event_t;
+
+typedef struct __ne_q {
+ int ne_local;
+ int ne_nodeid;
+ int ne_state;
+ int ne_clean;
+} node_event_t;
+
+typedef struct __cfg_q {
+ int cfg_version;
+ int cfg_oldversion;
+} config_event_t;
+
+typedef struct __user_q {
+ char u_name[128];
+ msgctx_t *u_ctx;
+ int u_request;
+ int u_arg1;
+ int u_arg2;
+ int u_target; /* Node ID */
+} user_event_t;
+
+typedef enum {
+ EVENT_NONE=0,
+ EVENT_CONFIG,
+ EVENT_NODE,
+ EVENT_RG,
+ EVENT_USER
+} event_type_t;
+
+/* Data that's distributed which indicates which
+ node is the event master */
+typedef struct __rgm {
+ uint32_t m_magic;
+ uint32_t m_nodeid;
+ uint64_t m_master_time;
+ uint8_t m_reserved[112];
+} event_master_t;
+
+#define swab_event_master_t(ptr)
+{
+ swab32((ptr)->m_nodeid);
+ swab32((ptr)->m_magic);
+ swab64((ptr)->m_master_time);
+}
+
+/* Just a magic # to help us ensure we've got good
+ date from VF */
+#define EVENT_MASTER_MAGIC 0xfabab0de
+
+/* Event structure - internal to the event subsystem; use
+ the queueing functions below which allocate this struct
+ and pass it to the event handler */
+typedef struct _event {
+ /* Not used dynamically - part of config info */
+ list_head();
+ char *ev_name;
+ char *ev_script;
+ char *ev_script_file;
+ int ev_prio;
+ int ev_pad;
+ /* --- end config part */
+ int ev_type; /* config & generated by rgmanager*/
+ int ev_transaction;
+ union {
+ group_event_t group;
+ node_event_t node;
+ config_event_t config;
+ user_event_t user;
+ } ev;
+} event_t;
+
+#define EVENT_PRIO_COUNT 100
+
+typedef struct _event_table {
+ int max_prio;
+ int pad;
+ event_t *entries[0];
+} event_table_t;
+
+
+int construct_events(int ccsfd, event_table_t **);
+void deconstruct_events(event_table_t **);
+void print_events(event_table_t *);
+
+/* Does the event match a configured event? */
+int event_match(event_t *pattern, event_t *actual);
+
+/* Event queueing functions. */
+void node_event_q(int local, int nodeID, int state, int clean);
+void rg_event_q(char *name, uint32_t state, int owner, int last);
+void user_event_q(char *svc, int request, int arg1, int arg2,
+ int target, msgctx_t *ctx);
+void config_event_q(int old_version, int new_version);
+
+/* Call this to see if there's a master. */
+int event_master_info_cached(event_master_t *);
+
+/* Call this to get the node ID of the current
+ master *or* become the master if none exists */
+int event_master(void);
+
+/* Setup */
+int central_events_enabled(void);
+void set_central_events(int flag);
+int slang_process_event(event_table_t *event_table, event_t *ev);
+
+/* For distributed events. */
+void set_transition_throttling(int nsecs);
+
+/* Simplified service start. */
+int service_op_start(char *svcName, int *target_list, int target_list_len,
+ int *new_owner);
+int service_op_stop(char *svcName, int do_disable, int event_type);
+
+
+#endif
--- cluster/rgmanager/include/resgroup.h 2007/11/30 20:36:17 1.24
+++ cluster/rgmanager/include/resgroup.h 2007/11/30 21:36:28 1.25
@@ -67,9 +67,16 @@
#define RG_PORT 177
+
+/* Constants moved to src/clulib/constants.c */
+/* DO NOT EDIT */
#define RG_MAGIC 0x11398fed
@@ -140,7 +148,7 @@
int group_op(char *rgname, int op);
void rg_init(void);
-/* FOOM */
+/* Basic service operations */
int svc_start(char *svcName, int req);
int svc_stop(char *svcName, int error);
int svc_status(char *svcName);
@@ -157,7 +165,8 @@
int max, uint32_t target, int arg0, int arg1);
void send_response(int ret, int node, request_t *req);
-void send_ret(msgctx_t *ctx, char *name, int ret, int req);
+void send_ret(msgctx_t *ctx, char *name, int ret, int orig_request,
+ int new_owner);
/* do this op on all resource groups. The handler for the request
will sort out whether or not it's a valid request given the state */
@@ -168,6 +177,7 @@
/* from rg_state.c */
int set_rg_state(char *name, rg_state_t *svcblk);
int get_rg_state(char *servicename, rg_state_t *svcblk);
+int get_rg_state_local(char *servicename, rg_state_t *svcblk);
uint32_t best_target_node(cluster_member_list_t *allowed, uint32_t owner,
char *rg_name, int lock);
@@ -192,6 +202,10 @@
int my_id(void);
/* Return codes */
+#define RG_EDOMAIN -15 /* Service not runnable given the
+ set of nodes and its failover
+ domain */
+#define RG_ESCRIPT -14 /* S/Lang script failed */
#define RG_EFENCE -13 /* Fencing operation pending */
#define RG_ENODE -12 /* Node is dead/nonexistent */
#define RG_EFROZEN -11 /* Service is frozen */
@@ -209,6 +223,7 @@
#define RG_YES 1
#define RG_NO 2
+
const char *rg_strerror(int val);
--- cluster/rgmanager/include/reslist.h 2007/11/30 20:36:17 1.24
+++ cluster/rgmanager/include/reslist.h 2007/11/30 21:36:28 1.25
@@ -202,6 +202,8 @@
void print_domains(fod_t **domains);
int node_should_start(int nodeid, cluster_member_list_t *membership,
char *rg_name, fod_t **domains);
+int node_domain_set(fod_t *domain, int **ret, int *retlen);
+int node_domain_set_safe(char *domainname, int **ret, int *retlen, int *flags);
/*
Internal functions; shouldn't be needed.
--- cluster/rgmanager/include/restart_counter.h 2007/11/30 20:36:17 1.2
+++ cluster/rgmanager/include/restart_counter.h 2007/11/30 21:36:28 1.3
@@ -1,3 +1,22 @@
+/*
+ Copyright Red Hat, Inc. 2007
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 as published
+ by the Free Software Foundation.
+
+ 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; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
+ MA 02139, USA.
+*/
+/* Time-based restart counters for rgmanager */
+
#ifndef _RESTART_COUNTER_H
#define _RESTART_COUNTER_H
--- cluster/rgmanager/include/rg_locks.h 2006/12/18 21:55:27 1.3
+++ cluster/rgmanager/include/rg_locks.h 2007/11/30 21:36:28 1.4
@@ -1,3 +1,20 @@
+/*
+ Copyright Red Hat, Inc. 2004-2007
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 as published
+ by the Free Software Foundation.
+
+ 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; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
+ MA 02139, USA.
+*/
#ifndef __RG_LOCKS_H
#define __RG_LOCKS_H
--- cluster/rgmanager/include/rg_queue.h 2006/07/19 18:43:32 1.6
+++ cluster/rgmanager/include/rg_queue.h 2007/11/30 21:36:28 1.7
@@ -1,3 +1,20 @@
+/*
+ Copyright Red Hat, Inc. 2004-2007
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 as published
+ by the Free Software Foundation.
+
+ 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; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
+ MA 02139, USA.
+*/
#ifndef _RG_QUEUE_H
#define _RG_QUEUE_H
#include <list.h>
@@ -19,7 +36,7 @@
uint32_t rr_target; /** Target node */
uint32_t rr_arg0; /** Integer argument */
uint32_t rr_arg1; /** Integer argument */
- uint32_t rr_arg3; /** Integer argument */
+ uint32_t rr_arg2; /** Integer argument */
uint32_t rr_line; /** Line no */
msgctx_t * rr_resp_ctx; /** FD to send response */
char *rr_file; /** Who made req */
@@ -42,5 +59,7 @@
void rq_free(request_t *foo);
#endif
/cvs/cluster/cluster/rgmanager/src/clulib/sets.c,v --> standard output
revision 1.1
--- cluster/rgmanager/src/clulib/sets.c
+++ - 2007-11-30 21:36:30.630539000 +0000
@@ -0,0 +1,370 @@
+/*
+ Copyright Red Hat, Inc. 2007
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 as published
+ by the Free Software Foundation.
+
+ 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; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
+ MA 02139, USA.
+*/
+/**
+ @file sets.c - Order-preserving set functions (union / intersection / delta)
+ (designed for integer types; a la int, uint64_t, etc...)
+ @author Lon Hohberger <lhh at redhat.com>
+ */
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sets.h>
+#include <sys/time.h>
+
+
+/**
+ Add a value to a set. This function disregards an add if the value is already
+ in the set. Note that the maximum length of set s must be preallocated; this
+ function doesn't do error or bounds checking.
+
+ @param s Set to modify
+ @param curlen Current length (modified if added)
+ @param val Value to add
+ @return 0 if not added, 1 if added
+ */
+int
+s_add(set_type_t *s, int *curlen, set_type_t val)
+{
+ int idx=0;
+
+ for (; idx < *curlen; idx++)
+ if (s[idx] == val)
+ return 0;
+ s[*curlen] = val;
+ ++(*curlen);
+ return 1;
+}
+
+
+/**
+ Union-set function. Allocates and returns a new set which is the union of
+ the two given sets 'left' and 'right'. Also returns the new set length.
+
+ @param left Left set - order is preserved on this set; that is,
+ this is the set where the caller cares about ordering.
+ @param ll Length of left set.
+ @param right Right set - order is not preserved on this set during
+ the union operation
+ @param rl Length of right set
+ @param ret Return set. Should * not * be preallocated.
+ @param retl Return set length. Should be ready to accept 1 integer
+ upon calling this function
+ @return 0 on success, -1 on error
+ */
+int
+s_union(set_type_t *left, int ll, set_type_t *right, int rl,
+ set_type_t **ret, int *retl)
+{
+ int l, r, cnt = 0, total;
+
+ total = ll + rl; /* Union will never exceed both sets */
+
+ *ret = malloc(sizeof(set_type_t)*total);
+ if (!*ret) {
+ return -1;
+ }
+ memset((void *)(*ret), 0, sizeof(set_type_t)*total);
+
+ cnt = 0;
+
+ /* Add all the ones on the left */
+ for (l = 0; l < ll; l++)
+ s_add(*ret, &cnt, left[l]);
+
+ /* Add the ones on the left */
+ for (r = 0; r < rl; r++)
+ s_add(*ret, &cnt, right[r]);
+
+ *retl = cnt;
+
+ return 0;
+}
+
+
+/**
+ Intersection-set function. Allocates and returns a new set which is the
+ intersection of the two given sets 'left' and 'right'. Also returns the new
+ set length.
+
+ @param left Left set - order is preserved on this set; that is,
+ this is the set where the caller cares about ordering.
+ @param ll Length of left set.
+ @param right Right set - order is not preserved on this set during
+ the union operation
+ @param rl Length of right set
+ @param ret Return set. Should * not * be preallocated.
+ @param retl Return set length. Should be ready to accept 1 integer
+ upon calling this function
+ @return 0 on success, -1 on error
+ */
+int
+s_intersection(set_type_t *left, int ll, set_type_t *right, int rl,
+ set_type_t **ret, int *retl)
+{
+ int l, r, cnt = 0, total;
+
+ total = ll; /* Intersection will never exceed one of the two set
+ sizes */
+
+ *ret = malloc(sizeof(set_type_t)*total);
+ if (!*ret) {
+ return -1;
+ }
+ memset((void *)(*ret), 0, sizeof(set_type_t)*total);
+
+ cnt = 0;
+ /* Find duplicates */
+ for (l = 0; l < ll; l++) {
+ for (r = 0; r < rl; r++) {
+ if (left[l] != right[r])
+ continue;
+ if (s_add(*ret, &cnt, right[r]))
+ break;
+ }
+ }
+
+ *retl = cnt;
+ return 0;
+}
+
+
+/**
+ Delta-set function. Allocates and returns a new set which is the delta (i.e.
+ numbers not in both sets) of the two given sets 'left' and 'right'. Also
+ returns the new set length.
+
+ @param left Left set - order is preserved on this set; that is,
+ this is the set where the caller cares about ordering.
+ @param ll Length of left set.
+ @param right Right set - order is not preserved on this set during
+ the union operation
+ @param rl Length of right set
+ @param ret Return set. Should * not * be preallocated.
+ @param retl Return set length. Should be ready to accept 1 integer
+ upon calling this function
+ @return 0 on success, -1 on error
+ */
+int
+s_delta(set_type_t *left, int ll, set_type_t *right, int rl,
+ set_type_t **ret, int *retl)
+{
+ int l, r, cnt = 0, total, found;
+
+ total = ll + rl; /* Union will never exceed both sets */
+
+ *ret = malloc(sizeof(set_type_t)*total);
+ if (!*ret) {
+ return -1;
+ }
+ memset((void *)(*ret), 0, sizeof(set_type_t)*total);
+
+ cnt = 0;
+
+ /* not efficient, but it works */
+ /* Add all the ones on the left */
+ for (l = 0; l < ll; l++) {
+ found = 0;
+ for (r = 0; r < rl; r++) {
+ if (right[r] == left[l]) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found)
+ continue;
+ s_add(*ret, &cnt, left[l]);
+ }
+
+
+ /* Add all the ones on the right*/
+ for (r = 0; r < rl; r++) {
+ found = 0;
+ for (l = 0; l < ll; l++) {
+ if (right[r] == left[l]) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found)
+ continue;
+ s_add(*ret, &cnt, right[r]);
+ }
+
+ *retl = cnt;
+
+ return 0;
+}
+
+
+/**
+ Subtract-set function. Allocates and returns a new set which is the
+ subtraction of the right set from the left set.
+ Also returns the new set length.
+
+ @param left Left set - order is preserved on this set; that is,
+ this is the set where the caller cares about ordering.
+ @param ll Length of left set.
+ @param right Right set - order is not preserved on this set during
+ the union operation
+ @param rl Length of right set
+ @param ret Return set. Should * not * be preallocated.
+ @param retl Return set length. Should be ready to accept 1 integer
+ upon calling this function
+ @return 0 on success, -1 on error
+ */
+int
+s_subtract(set_type_t *left, int ll, set_type_t *right, int rl,
+ set_type_t **ret, int *retl)
+{
+ int l, r, cnt = 0, total, found;
+
+ total = ll; /* Union will never exceed left set length*/
+
+ *ret = malloc(sizeof(set_type_t)*total);
+ if (!*ret) {
+ return -1;
+ }
+ memset((void *)(*ret), 0, sizeof(set_type_t)*total);
+
+ cnt = 0;
+
+ /* not efficient, but it works */
+ for (l = 0; l < ll; l++) {
+ found = 0;
+ for (r = 0; r < rl; r++) {
+ if (right[r] == left[l]) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found)
+ continue;
+ s_add(*ret, &cnt, left[l]);
+ }
+
+ *retl = cnt;
+
+ return 0;
+}
+
+
+/**
+ Shuffle-set function. Weakly randomizes ordering of a set in-place.
+
+ @param set Set to randomize
+ @param sl Length of set
+ @return 0
+ */
+int
+s_shuffle(set_type_t *set, int sl)
+{
+ int x, newidx;
+ unsigned r_state = 0;
+ set_type_t t;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ r_state = (int)(tv.tv_usec);
+
+ for (x = 0; x < sl; x++) {
+ newidx = (rand_r(&r_state) % sl);
+ if (newidx == x)
+ continue;
+ t = set[x];
+ set[x] = set[newidx];
+ set[newidx] = t;
+ }
+
+ return 0;
+}
+
+
+#ifdef STANDALONE
+/* Testbed */
+/*
+ gcc -o sets sets.c -DSTANDALONE -ggdb -I../../include
+ -Wall -Werror -Wstrict-prototypes -Wextra
+ */
+int
+main(int __attribute__ ((unused)) argc, char __attribute__ ((unused)) **argv)
+{
+ set_type_t a[] = { 1, 2, 3, 3, 3, 2, 2, 3 };
+ set_type_t b[] = { 2, 3, 4 };
+ set_type_t *i;
+ int ilen = 0, x;
+
+ s_union(a, 8, b, 3, &i, &ilen);
+
+ /* Should return length of 4 - { 1 2 3 4 } */
+ printf("set_union [%d] = ", ilen);
+ for ( x = 0; x < ilen; x++) {
+ printf("%d ", (int)i[x]);
+ }
+ printf("
");
+
+ s_shuffle(i, ilen);
+ printf("shuffled [%d] = ", ilen);
+ for ( x = 0; x < ilen; x++) {
+ printf("%d ", (int)i[x]);
+ }
+ printf("
");
+
+
+ free(i);
+
+ /* Should return length of 2 - { 2 3 } */
+ s_intersection(a, 8, b, 3, &i, &ilen);
+
+ printf("set_intersection [%d] = ", ilen);
+ for ( x = 0; x < ilen; x++) {
+ printf("%d ", (int)i[x]);
+ }
+ printf("
");
+
+ free(i);
+
+ /* Should return length of 2 - { 1 4 } */
+ s_delta(a, 8, b, 3, &i, &ilen);
+
+ printf("set_delta [%d] = ", ilen);
+ for ( x = 0; x < ilen; x++) {
+ printf("%d ", (int)i[x]);
+ }
+ printf("
");
+
+ free(i);
+
+ /* Should return length of 1 - { 1 } */
+ s_subtract(a, 8, b, 3, &i, &ilen);
+
+ printf("set_subtract [%d] = ", ilen);
+ for ( x = 0; x < ilen; x++) {
+ printf("%d ", (int)i[x]);
+ }
+ printf("
");
+
+ free(i);
+
+
+ return 0;
+}
+#endif
--- cluster/rgmanager/src/clulib/Makefile 2007/11/12 08:17:00 1.18
+++ cluster/rgmanager/src/clulib/Makefile 2007/11/30 21:36:28 1.19
@@ -19,7 +19,7 @@
OBJS1= clulog.o daemon_init.o signals.o msgsimple.o
gettid.o rg_strings.o message.o members.o fdops.o
lock.o cman.o vft.o msg_cluster.o msg_socket.o
- wrap_lock.o
+ wrap_lock.o sets.o