diff options
author | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
---|---|---|
committer | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
commit | b2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch) | |
tree | cf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/slapd/conntable.c | |
download | ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.gz ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.xz ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.zip |
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/servers/slapd/conntable.c')
-rw-r--r-- | ldap/servers/slapd/conntable.c | 515 |
1 files changed, 515 insertions, 0 deletions
diff --git a/ldap/servers/slapd/conntable.c b/ldap/servers/slapd/conntable.c new file mode 100644 index 00000000..8297971c --- /dev/null +++ b/ldap/servers/slapd/conntable.c @@ -0,0 +1,515 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* Connection Table */ + +#include "fe.h" + +Connection_Table * +connection_table_new(int table_size) +{ + Connection_Table *ct; + int i = 0; + + + ct= (Connection_Table*)slapi_ch_calloc( 1, sizeof(Connection_Table) ); + ct->size= table_size; + ct->c = (Connection *)slapi_ch_calloc( 1, table_size * sizeof(Connection) ); + ct->fd = (struct POLL_STRUCT *)slapi_ch_calloc(1, table_size * sizeof(struct POLL_STRUCT)); + ct->table_mutex = PR_NewLock(); + + /* We rely on the fact that we called calloc, which zeros the block, so we don't + * init any structure element unless a zero value is troublesome later + */ + for ( i = 0; i < table_size; i++ ) + { + int invalid_socket; + unsigned long maxbersize= config_get_maxbersize(); + /* DBDB---move this out of here once everything works */ + ct->c[i].c_sb = ber_sockbuf_alloc(); + invalid_socket = SLAPD_INVALID_SOCKET; + ber_sockbuf_set_option( ct->c[i].c_sb, LBER_SOCKBUF_OPT_DESC, &invalid_socket ); + ct->c[i].c_sd = SLAPD_INVALID_SOCKET; + ber_sockbuf_set_option( ct->c[i].c_sb, LBER_SOCKBUF_OPT_NO_READ_AHEAD, LBER_OPT_ON ); + ber_sockbuf_set_option( ct->c[i].c_sb, LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE, &maxbersize ); +#ifndef _WIN32 + /* all connections start out invalid */ + ct->fd[i].fd = SLAPD_INVALID_SOCKET; +#endif + /* The connection table has a double linked list running through it. + * This is used to find out which connections should be looked at + * in the poll loop. Slot 0 in the table is always the head of + * the linked list. Each slot has a c_next and c_prev which are + * pointers back into the array of connection slots. */ + ct->c[i].c_next = NULL; + ct->c[i].c_prev = NULL; + ct->c[i].c_ci= i; + ct->c[i].c_fdi= SLAPD_INVALID_SOCKET_INDEX; + } + return ct; +} + +void connection_table_free(Connection_Table *ct) +{ + int i; + for (i = 0; i < ct->size; i++) + { + /* Free the contents of the connection structure */ + Connection *c= &(ct->c[i]); + connection_done(c); + } + slapi_ch_free((void**)&ct->c); + slapi_ch_free((void**)&ct->fd); + PR_DestroyLock(ct->table_mutex); + slapi_ch_free((void**)&ct); +} + + +#ifdef _WIN32 +/* + * This function looks up connection by nspr fd. It is + * slow because it iterrates through the entire connection + * array. Currently, it is only used on NT in secure_read_function + * to handle I/O timeout on SSL socket we should almost never + * happen. + */ +Connection* +connection_table_get_connection_from_fd(Connection_Table *ct,PRFileDesc *prfd) +{ + int i; + for (i = 0; i < ct->size; i++) + { + if (ct->c[i].c_prfd == prfd) + { + return (&(ct->c[i])); + } + } + + return NULL; +} +#endif + +void +connection_table_abandon_all_operations(Connection_Table *ct) +{ + int i; + for ( i = 0; i < ct->size; i++ ) + { + if ( ct->c[i].c_mutex != NULL ) + { + PR_Lock( ct->c[i].c_mutex ); + connection_abandon_operations( &ct->c[i] ); + PR_Unlock( ct->c[i].c_mutex ); + } + } +} + +/* Given a file descriptor for a socket, this function will return + * a slot in the connection table to use. + * + * Note: this function is only called from the slapd_daemon (listener) + * thread, which means it will never be called by two threads at + * the same time. + * + * Returns a Connection on success + * Returns NULL on failure + */ +Connection * +connection_table_get_connection(Connection_Table *ct, int sd) +{ + Connection *c= NULL; + int index, count; + + index = sd % ct->size; + for( count = 0; count < ct->size; count++, index = (index + 1) % ct->size) + { + /* Do not use slot 0, slot 0 is head of the list of active connections */ + if ( index == 0 ) + { + continue; + } + else if( ct->c[index].c_mutex == NULL ) + { + break; + } + + if( connection_is_free (&(ct->c[index]))) + { + break; + } + } + + if ( count < ct->size ) + { + /* Found an available Connection */ + c= &(ct->c[index]); + PR_ASSERT(c->c_next==NULL); + PR_ASSERT(c->c_prev==NULL); + PR_ASSERT(c->c_extension==NULL); + if ( c->c_mutex == NULL ) + { + PR_Lock( ct->table_mutex ); + c->c_mutex = PR_NewLock(); + c->c_pdumutex = PR_NewLock(); + PR_Unlock( ct->table_mutex ); + if ( c->c_mutex == NULL || c->c_pdumutex == NULL ) + { + c->c_mutex = NULL; + c->c_pdumutex = NULL; + LDAPDebug( LDAP_DEBUG_ANY,"PR_NewLock failed\n",0, 0, 0 ); + c= NULL; + } + } + /* Let's make sure there's no cruft left on there from the last time this connection was used. */ + /* Note: no need to lock c->c_mutex because this function is only + * called by one thread (the slapd_daemon thread), and if we got this + * far then `c' is not being used by any operation threads, etc. + */ + connection_cleanup(c); + } + else + { + /* couldn't find a Connection */ + LDAPDebug( LDAP_DEBUG_CONNS, "max open connections reached\n", 0, 0, 0); + } + return c; +} + +/* active connection iteration functions */ + +Connection* +connection_table_get_first_active_connection (Connection_Table *ct) +{ + return ct->c[0].c_next; +} + +Connection* +connection_table_get_next_active_connection (Connection_Table *ct, Connection *c) +{ + return c->c_next; +} + +int connection_table_iterate_active_connections(Connection_Table *ct, void* arg, Connection_Table_Iterate_Function f) +{ + /* Locking in this area seems rather undeveloped, I think because typically only one + * thread accesses the connection table (daemon thread). But now we allow other threads + * to iterate over the table. So we use the "new mutex mutex" to lock the table. + */ + Connection *current_conn = NULL; + int ret = 0; + PR_Lock(ct->table_mutex); + current_conn = connection_table_get_first_active_connection (ct); + while (current_conn) { + ret = f(current_conn, arg); + if (ret) { + break; + } + current_conn = connection_table_get_next_active_connection (ct, current_conn); + } + PR_Unlock(ct->table_mutex); + return ret; +} + +static void +connection_table_dump_active_connection (Connection *c) +{ + slapi_log_error(SLAPI_LOG_FATAL, "connection", "conn=%p fd=%d refcnt=%d c_flags=%d\n" + "mutex=%p next=%p prev=%p\n\n", c, c->c_sd, c->c_refcnt, c->c_flags, + c->c_mutex, c->c_next, c->c_prev); +} + +static void +connection_table_dump_active_connections (Connection_Table *ct) +{ + Connection* c; + + PR_Lock(ct->table_mutex); + slapi_log_error(SLAPI_LOG_FATAL, "connection", "********** BEGIN DUMP ************\n"); + c = connection_table_get_first_active_connection (ct); + while (c) + { + connection_table_dump_active_connection (c); + c = connection_table_get_next_active_connection (ct, c); + } + + slapi_log_error(SLAPI_LOG_FATAL, "connection", "********** END DUMP ************\n"); + PR_Unlock(ct->table_mutex); +} + +/* + * There's a double linked list of active connections running through the array + * of connections. This function removes a connection (by index) from that + * list. This list is used to find the connections that should be used in the + * poll call. + */ +void +connection_table_move_connection_out_of_active_list(Connection_Table *ct,Connection *c) +{ + /* we always have previous element because list contains a dummy header */; + PR_ASSERT (c->c_prev); + + /* slapi_log_error(SLAPI_LOG_FATAL, "connection", "Moving connection out of active list\n"); + connection_table_dump_active_connection (c);*/ + + /* + * Note: the connection will NOT be moved off the active list if any other threads still hold + * a reference to the connection (that is, its reference count must be 1 or less). + */ + if(c->c_refcnt > 1) return; + + /* We need to lock here because we're modifying the linked list */ + PR_Lock(ct->table_mutex); + + c->c_prev->c_next = c->c_next; + + if (c->c_next) + { + c->c_next->c_prev = c->c_prev; + } + + connection_release_nolock (c); + + connection_cleanup (c); + + PR_Unlock(ct->table_mutex); + + /* connection_table_dump_active_connections (ct); */ +} + +/* + * There's a double linked list of active connections running through the array + * of connections. This function adds a connection (by index) to the head of + * that list. This list is used to find the connections that should be used in the + * poll call. + */ +void +connection_table_move_connection_on_to_active_list(Connection_Table *ct,Connection *c) +{ + PR_ASSERT(c->c_next==NULL); + PR_ASSERT(c->c_prev==NULL); + + PR_Lock(ct->table_mutex); + + connection_acquire_nolock (c); + + /* slapi_log_error(SLAPI_LOG_FATAL, "connection", "Moving connection into active list\n"); + connection_table_dump_active_connection (c);*/ + + c->c_next = ct->c[0].c_next; + if ( c->c_next != NULL ) + { + c->c_next->c_prev = c; + } + c->c_prev = &(ct->c[0]); + ct->c[0].c_next = c; + + PR_Unlock(ct->table_mutex); + + /* connection_table_dump_active_connections (ct); */ +} + +/* + * Replace the following attributes within the entry 'e' with + * information about the connection table: + * connection // multivalued; one value for each active connection + * currentconnections // single valued; an integer count + * totalconnections // single valued; an integer count + * dtablesize // single valued; an integer size + * readwaiters // single valued; an integer count + */ +void +connection_table_as_entry(Connection_Table *ct, Slapi_Entry *e) +{ + char buf[BUFSIZ]; + struct berval val; + struct berval *vals[2]; + int i, nconns, nreadwaiters; + struct tm utm; + + vals[0] = &val; + vals[1] = NULL; + + attrlist_delete( &e->e_attrs, "connection"); + nconns = 0; + nreadwaiters = 0; + for ( i = 0; i < (ct!=NULL?ct->size:0); i++ ) + { + PR_Lock( ct->table_mutex ); + if ( (ct->c[i].c_mutex == NULL) || (ct->c[i].c_mutex == (PRLock*)-1) ) + { + PR_Unlock( ct->table_mutex ); + continue; + } + /* Can't take c_mutex if holding table_mutex; temporarily unlock */ + PR_Unlock( ct->table_mutex ); + + PR_Lock( ct->c[i].c_mutex ); + if ( ct->c[i].c_sd != SLAPD_INVALID_SOCKET ) + { + char buf2[20]; + int lendn = ct->c[i].c_dn ? strlen(ct->c[i].c_dn) : 6; /* "NULLDN" */ + char *bufptr = &buf[0]; + char *newbuf = NULL; + + nconns++; + if ( ct->c[i].c_gettingber ) + { + nreadwaiters++; + } + +#ifdef _WIN32 + { + struct tm *pt; + pt = gmtime( &ct->c[i].c_starttime ); + memcpy(&utm, pt, sizeof(struct tm) ); + } +#else + gmtime_r( &ct->c[i].c_starttime, &utm ); +#endif + strftime( buf2, sizeof(buf2), "%Y%m%d%H%M%SZ", &utm ); + + if (lendn > (BUFSIZ - 46)) { + /* + * 46 = 4 for the "i" couter + 20 for buf2 + + * 10 for c_opsinitiated + 10 for c_opscompleted + + * 1 for c_gettingber + 1 + */ + newbuf = (char *) slapi_ch_malloc(lendn + 46); + bufptr = newbuf; + } + + sprintf( bufptr, "%d:%s:%d:%d:%s%s:%s", i, + buf2, + ct->c[i].c_opsinitiated, + ct->c[i].c_opscompleted, + ct->c[i].c_gettingber ? "r" : "", + "", + ct->c[i].c_dn ? ct->c[i].c_dn : "NULLDN" ); + val.bv_val = bufptr; + val.bv_len = strlen( bufptr ); + attrlist_merge( &e->e_attrs, "connection", vals ); + if (newbuf) { + slapi_ch_free((void **) &newbuf); + } + } + PR_Unlock( ct->c[i].c_mutex ); + } + + sprintf( buf, "%d", nconns ); + val.bv_val = buf; + val.bv_len = strlen( buf ); + attrlist_replace( &e->e_attrs, "currentconnections", vals ); + + PR_Lock( num_conns_mutex ); + sprintf( buf, "%d", num_conns ); + PR_Unlock( num_conns_mutex ); + val.bv_val = buf; + val.bv_len = strlen( buf ); + attrlist_replace( &e->e_attrs, "totalconnections", vals ); + + sprintf( buf, "%d", (ct!=NULL?ct->size:0) ); + val.bv_val = buf; + val.bv_len = strlen( buf ); + attrlist_replace( &e->e_attrs, "dtablesize", vals ); + + sprintf( buf, "%d", nreadwaiters ); + val.bv_val = buf; + val.bv_len = strlen( buf ); + attrlist_replace( &e->e_attrs, "readwaiters", vals ); +} + +void +connection_table_dump_activity_to_errors_log(Connection_Table *ct) +{ + int i; + for ( i = 0; i < ct->size; i++ ) + { + Connection *c= &(ct->c[i]); + if ( c->c_mutex != NULL ) + { + /* Find the connection we are referring to */ + int j= c->c_fdi; + PR_Lock( c->c_mutex ); + if ( c->c_sd != SLAPD_INVALID_SOCKET && c->c_prfd == ct->fd[j].fd ) + { + int r = ct->fd[j].out_flags & SLAPD_POLL_FLAGS; + if ( r ) + { + LDAPDebug( LDAP_DEBUG_CONNS,"activity on %d%s\n", i, r ? "r" : "",0 ); + } + } + PR_Unlock( c->c_mutex ); + } + } +} + +#if 0 +void dump_op_list(FILE *file, Operation *op); + +void +connection_table_dump(Connection_Table *ct) +{ + FILE *file; + + file = fopen("/tmp/slapd.conn", "a+"); + if (file != NULL) + { + int i; + fprintf(file, "=============pid=%d==================\n", getpid()); + for ( i = 0; i < ct->size; i++ ) + { + if ( (ct->c[i].c_sd == SLAPD_INVALID_SOCKET) && (ct->c[i].c_connid == 0) ) + { + continue; + } + fprintf(file, "c[%d].c_dn=0x%x\n", i, ct->c[i].c_dn); + dump_op_list(file, ct->c[i].c_ops); + fprintf(file, "c[%d].c_sb.sb_sd=%d\n", i, ct->c[i].c_sd); + fprintf(file, "c[%d].c_connid=%d\n", i, ct->c[i].c_connid); + fprintf(file, "c[%d].c_opsinitiated=%d\n", i, ct->c[i].c_opsinitiated); + fprintf(file, "c[%d].c_opscompleted=%d\n", i, ct->c[i].c_opscompleted); + } + fclose(file); + } +} + +static const char * +op_status2str( int o_status ) +{ + const char *s = "unknown"; + + switch( o_status ) { + case SLAPI_OP_STATUS_PROCESSING: + s = "processing"; + break; + case SLAPI_OP_STATUS_ABANDONED: + s = "abandoned"; + break; + case SLAPI_OP_STATUS_WILL_COMPLETE: + s = "will_complete"; + break; + case SLAPI_OP_STATUS_RESULT_SENT: + s = "result_sent"; + break; + } + + return s; +} + +void +dump_op_list(FILE *file, Operation *op) +{ + Operation *tmp; + + for ( tmp = op; tmp != NULL; tmp = tmp->o_next ) + { + fprintf(file, + "(o_msgid=%d, o_tag=%d, o_sdn=0x%x, o_opid=%d, o_connid=%d, o_status=%s)\n", + tmp->o_msgid, tmp->o_tag, slapi_sdn_get_dn(&tmp->o_sdn), tmp->o_connid, + *tmp->o_tid, op_status2str( tmp->o_status )); + } +} +#endif /* 0 */ + |