В Fri, 27 Nov 2009 20:49:16 +0300
Dmitry Banshchikov <[email protected]> пишет:

> Hello.
> 
> Jabberd2 support virtual domains. But, this support is limited. I
> mean, that we can not support new domains without adding them into
> sm.xml and restarting session manager process(as far as I know).
> More than that, if we need to support many virtuail domains - it is
> become a problem(about 10K. I want to support many domains, because 
> we have a lot of clients with a lot of domains(virtual hosting) and we
> want give everyone jabber support for domain.).
> 
> The problem is that if we have about 10k domains in our sm.xml,
> then restarting time of jabberd is about 15 minutes. Bigger part of
> this time is consumpted by router process.
> I have made some tests and understand, that router spend its time for
> this code:
> router.c: 307 line
> 
>     /* tell the new component about everyone else */
>     xhash_walk(comp->r->routes, _router_advertise_reverse, (void *)
>     comp);
> 
> I measure time for this call and number of elements in
> comp->r->routes. There are results:
> 1 elements is 0.000160000000
> 2 elements is 0.000610000000
> 3 elements is 0.000750000000
> 4 elements is 0.000430000000
> 5 elements is 0.000650000000
> 6 elements is 0.000540000000
> 
> --- --- ---
> 62731 elements is 0.141400000000
> 62732 elements is 0.141670000000
> 62733 elements is 0.143430000000
> 62734 elements is 0.141510000000
> 62735 elements is 0.141460000000
> 
> We can see, that this time consumption is significant.
> More than that, the problem is also that really we don't need to
> support all of this domains, but only those, for which we have
> accounts.
> 
> I have writen patch, which solve this problem(I believe).
> The idea is that we set handler for SIGALRM signal and every rldtime
> secs(new directive in sm.xml) get distinct lists of realms from
> authreg table. Than we check every realm in sm->avail list and if we
> have no record for this domain - we dynamically add it. Patch need
> some additional function with storage modules, but I think, this
> function which allow us to generate customize querys to data backend
> is helpful.
> 
> 
> 

Sorry. Here is the patch.


-- 

Dmitry Banshchikov
--- sm/main.c	2009-07-06 01:54:15.000000000 +0400
+++ sm/main.c	2009-11-27 17:05:09.000000000 +0300
@@ -117,6 +117,8 @@
     sm->retry_lost = j_atoi(config_get_one(sm->config, "router.retry.lost", 0), 3);
     if((sm->retry_sleep = j_atoi(config_get_one(sm->config, "router.retry.sleep", 0), 2)) < 1)
         sm->retry_sleep = 1;
+	if((sm->rldtime = j_atoi(config_get_one(sm->config, "router.rldtime", 0), 60)) < 1)
+		sm->rldtime = 1;
 
     sm->log_type = log_STDOUT;
     if(config_get(sm->config, "log") != NULL) {
@@ -167,6 +169,45 @@
     }
 }
 
+static void _sm_hosts_new(int signo) {
+	int			nsec, ns;
+	os_t		os;
+	os_object_t	o;
+	char		*str;
+	nad_t		nad;
+
+	nsec = sm->rldtime;
+
+	if (alarm(nsec) != 0) {
+		log_write(sm->log, LOG_NOTICE, "previous alarm timer was set");
+	}
+	if (storage_get_custom(sm->st, "distinct(realm)", "authreg", "1 = 1", &os) == st_SUCCESS) {
+		if (os_iter_first(os))
+			do {
+				o = os_iter_object(os);
+
+				if (os_object_get_str(os, o, "realm", &str)) {
+					/* Check this domain already configured */
+					if ( (xhash_get(sm->hosts, str) == NULL)) {
+						xhash_put(sm->hosts, pstrdup(xhash_pool(sm->hosts), str), sm);
+						nad = nad_new();
+						ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
+						nad_append_elem(nad, ns, "bind", 0);
+						nad_append_attr(nad, -1, "name", str);
+						nad_append_attr(nad, -1, "multi", "to");
+						sx_nad_write(sm->router, nad);
+						log_write(sm->log, LOG_NOTICE, "[%s] configured", str);
+					}
+
+				}
+
+			} while (os_iter_next(os));
+
+	}
+
+
+}
+
 static int _sm_router_connect(sm_t sm) {
     log_write(sm->log, LOG_NOTICE, "attempting connection to router at %s, port=%d", sm->router_ip, sm->router_port);
 
@@ -218,6 +259,7 @@
 
     jabber_signal(SIGINT, _sm_signal);
     jabber_signal(SIGTERM, _sm_signal);
+    jabber_signal(SIGALRM, _sm_hosts_new);
 #ifdef SIGHUP
     jabber_signal(SIGHUP, _sm_signal_hup);
 #endif
@@ -359,6 +401,8 @@
 
     sm->retry_left = sm->retry_init;
     _sm_router_connect(sm);
+    _sm_hosts_new(SIGALRM);
+	
     
     while(!sm_shutdown) {
         mio_run(sm->mio, 5);
--- sm/sm.h	2009-07-06 01:54:15.000000000 +0400
+++ sm/sm.h	2009-11-27 15:34:34.000000000 +0300
@@ -203,6 +203,8 @@
     int                 retry_sleep;        /**< sleep interval between retries */
     int                 retry_left;         /**< number of tries left before failure */
 
+    int                 rldtime;            /**< number of seconds between searching new hosts */	
+
     storage_t           st;                 /**< storage subsystem */
 
     mm_t                mm;                 /**< module subsystem */
@@ -606,6 +608,7 @@
     st_ret_t    (*put)(st_driver_t drv, const char *type, const char *owner, os_t os);
     /** get handler */
     st_ret_t    (*get)(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t *os);
+    st_ret_t    (*get_custom)(st_driver_t drv, const char *what, const char *from, const char *cond, os_t *os);
     /** count handler */
     st_ret_t    (*count)(st_driver_t drv, const char *type, const char *owner, const char *filter, int *count);
     /** delete handler */
--- sm/storage.c	2009-07-06 01:54:15.000000000 +0400
+++ sm/storage.c	2009-11-27 16:08:41.000000000 +0300
@@ -241,6 +241,30 @@
     return (drv->get)(drv, type, owner, filter, os);
 }
 
+st_ret_t storage_get_custom(storage_t st, const char *what, const char *from, const char *cond, os_t *os) {
+    st_driver_t drv;
+    st_ret_t    ret;
+
+    log_debug(ZONE, "storage_get_custom: what=%s from=%s cond=%s", what, from, cond);
+
+    /* find the handler for this type */
+    drv = xhash_get(st->types, from);
+    if(drv == NULL) {
+	drv = st->default_drv;
+	if (drv == NULL) {
+	    log_debug(ZONE, "no driver associated with type, and no default driver");
+	    return st_NOTIMPL;
+	}
+
+	ret = storage_add_type(st, drv->name, from);
+	if (ret != st_SUCCESS)
+	    return ret;
+    }
+
+    return (drv->get_custom)(drv, what, from, cond, os);
+
+}
+
 st_ret_t storage_count(storage_t st, const char *type, const char *owner, const char *filter, int *count) {
     st_driver_t drv;
     st_ret_t ret;
--- storage/storage_mysql.c	2009-07-06 01:54:16.000000000 +0400
+++ storage/storage_mysql.c	2009-11-27 16:33:24.000000000 +0300
@@ -425,6 +425,128 @@
     return st_SUCCESS;
 }
 
+static st_ret_t _st_mysql_get_custom(st_driver_t drv, const char *what, const char *from, const char *cond,  os_t *os) {
+    drvdata_t data = (drvdata_t) drv->private;
+    char *buf = NULL;
+    int buflen = 0;
+    MYSQL_RES *res;
+    int ntuples, nfields, i, j;
+    MYSQL_FIELD *fields;
+    MYSQL_ROW tuple;
+    unsigned long *lengths;
+    os_object_t o;
+    char *val;
+    os_type_t ot;
+    int ival;
+    char tbuf[255];
+
+    if ( (mysql_ping(data->conn)) !=0) {
+	log_write(drv->st->sm->log, LOG_ERR, "mysql: connection to database lost");
+	return st_FAILED;
+    }
+
+    if (data->prefix != NULL) {
+	snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, what);
+    }
+
+    MYSQL_SAFE(buf, strlen(what) + strlen(from) + strlen(cond) + 21, buflen)
+    sprintf(buf, "SELECT %s FROM %s WHERE %s", what, from, cond);
+
+    log_debug(ZONE, "prepared sql: %s", buf);
+    
+    if (mysql_query(data->conn, buf) != 0) {
+	log_write(drv->st->sm->log, LOG_ERR, "mysql: sql select failed: %s", mysql_error(data->conn));
+	free(buf);
+	return st_FAILED;
+    }
+
+    free(buf);
+
+    res = mysql_store_result(data->conn);
+    if (res == NULL) {
+	log_write(drv->st->sm->log, LOG_ERR, "mysql: sql result retrieval failed: %s", mysql_error(data->conn));
+	return st_FAILED;
+    }
+
+    ntuples = mysql_num_rows(res);
+    if (ntuples == 0) {
+	mysql_free_result(res);
+	return st_NOTFOUND;
+    }
+
+    log_debug(ZONE, "%d tupes returned", ntuples);
+
+    nfields = mysql_num_fields(res);
+
+    if (nfields == 0) {
+        log_debug(ZONE, "weird, tuples were returned but no fields *shrug*");
+        mysql_free_result(res);
+        return st_NOTFOUND;
+    }
+
+    fields = mysql_fetch_fields(res);
+
+    *os = os_new();
+
+
+    for (i = 0; i < ntuples; i++) {
+	o = os_object_new(*os);
+
+	if ((tuple = mysql_fetch_row(res)) == NULL) 
+	    break; 
+
+
+	for (j = 0; j < nfields; j++) {
+  	    if (tuple[j] == NULL)
+	        continue;
+
+	    lengths = mysql_fetch_lengths(res);
+	    switch(fields[j].type) {
+		case FIELD_TYPE_TINY:
+		    ot = os_type_BOOLEAN;
+		    break;
+		case FIELD_TYPE_LONG:
+		    ot = os_type_INTEGER;
+		    break;
+		case FIELD_TYPE_BLOB:
+		case FIELD_TYPE_VAR_STRING:
+		    ot = os_type_STRING;
+		    break;
+		default:
+		    log_debug(ZONE, "unknow filed type %d, ingoring it", fields[j].type);
+		    continue;
+	    }
+
+	    val = tuple[j];
+
+	    switch(ot) {
+		case os_type_BOOLEAN:
+		    ival = (val[0] == '0') ? 0 : 1;
+		    os_object_put(o, fields[j].name, &ival, ot);
+		    break;
+
+		case os_type_INTEGER:
+		    ival = atoi(val);
+		    os_object_put(o, fields[j].name, &ival, ot);
+		    break;
+		case os_type_STRING:
+		    os_object_put(o, fields[j].name, val, os_type_STRING);
+		    break;
+
+		case os_type_NAD:
+		case os_type_UNKNOWN:
+		    break;
+
+	    }
+	}
+    }
+
+    mysql_free_result(res);
+
+    return st_SUCCESS;
+    
+}
+
 static st_ret_t _st_mysql_count(st_driver_t drv, const char *type, const char *owner, const char *filter, int *count) {
     drvdata_t data = (drvdata_t) drv->private;
     char *cond, *buf = NULL;
@@ -630,6 +752,7 @@
     drv->put = _st_mysql_put;
     drv->count = _st_mysql_count;
     drv->get = _st_mysql_get;
+    drv->get_custom = _st_mysql_get_custom;
     drv->delete = _st_mysql_delete;
     drv->replace = _st_mysql_replace;
     drv->free = _st_mysql_free;

Reply via email to