static int test1() { GWBUF *buffer; char *(sql[100]); int result, length, residual; /* Poll tests */ ss_dfprintf(stderr, "testmodutil : Rudimentary tests."); buffer = gwbuf_alloc(100); ss_info_dassert(0 == modutil_is_SQL(buffer), "Default buffer should be diagnosed as not SQL"); /* There would ideally be some straightforward way to create a SQL buffer? */ ss_dfprintf(stderr, "\t..done\nExtract SQL from buffer"); ss_info_dassert(0 == modutil_extract_SQL(buffer, sql, &length), "Default buffer should fail"); ss_dfprintf(stderr, "\t..done\nExtract SQL from buffer different way?"); ss_info_dassert(0 == modutil_MySQL_Query(buffer, sql, &length, &residual), "Default buffer should fail"); ss_dfprintf(stderr, "\t..done\nReplace SQL in buffer"); ss_info_dassert(0 == modutil_replace_SQL(buffer, "select * from some_table;"), "Default buffer should fail"); ss_dfprintf(stderr, "\t..done\nTidy up."); gwbuf_free(buffer); ss_dfprintf(stderr, "\t..done\n"); return 0; }
int test2() { GWBUF *buffer; char len = 128; char query[129]; buffer = gwbuf_alloc(132); ss_info_dassert((buffer != NULL),"Buffer should not be null"); memset(query,';',128); memset(query+128,'\0',1); *((unsigned char*)buffer->start) = len; *((unsigned char*)buffer->start+1) = 0; *((unsigned char*)buffer->start+2) = 0; *((unsigned char*)buffer->start+3) = 1; *((unsigned char*)buffer->start+4) = 0x03; memcpy(buffer->start + 5,query,strlen(query)); char* result = modutil_get_SQL(buffer); ss_dassert(strcmp(result,query) == 0); gwbuf_free(buffer); free(result); ss_dfprintf(stderr, "\t..done\n"); return 0; }
/** * test1 Allocate a server and do lots of other things * */ static int test1() { SERVER *server; int result; char *status; /* Server tests */ ss_dfprintf(stderr, "testserver : creating server called MyServer"); server = server_alloc("MyServer", "HTTPD", 9876); skygw_log_sync_all(); //ss_info_dassert(NULL != service, "New server with valid protocol and port must not be null"); //ss_info_dassert(0 != service_isvalid(service), "Service must be valid after creation"); ss_dfprintf(stderr, "\t..done\nTest Parameter for Server."); ss_info_dassert(NULL == serverGetParameter(server, "name"), "Parameter should be null when not set"); serverAddParameter(server, "name", "value"); skygw_log_sync_all(); ss_info_dassert(0 == strcmp("value", serverGetParameter(server, "name")), "Parameter should be returned correctly"); ss_dfprintf(stderr, "\t..done\nTesting Unique Name for Server."); ss_info_dassert(NULL == server_find_by_unique_name("uniquename"), "Should not find non-existent unique name."); server_set_unique_name(server, "uniquename"); skygw_log_sync_all(); ss_info_dassert(server == server_find_by_unique_name("uniquename"), "Should find by unique name."); ss_dfprintf(stderr, "\t..done\nTesting Status Setting for Server."); status = server_status(server); skygw_log_sync_all(); ss_info_dassert(0 == strcmp("Running", status), "Status of Server should be Running by default."); if (NULL != status) free(status); server_set_status(server, SERVER_MASTER); status = server_status(server); skygw_log_sync_all(); ss_info_dassert(0 == strcmp("Master, Running", status), "Should find correct status."); server_clear_status(server, SERVER_MASTER); free(status); status = server_status(server); skygw_log_sync_all(); ss_info_dassert(0 == strcmp("Running", status), "Status of Server should be Running after master status cleared."); if (NULL != status) free(status); ss_dfprintf(stderr, "\t..done\nRun Prints for Server and all Servers."); printServer(server); printAllServers(); skygw_log_sync_all(); ss_dfprintf(stderr, "\t..done\nFreeing Server."); ss_info_dassert(0 != server_free(server), "Free should succeed"); ss_dfprintf(stderr, "\t..done\n"); return 0; }
/** * test1 Allocate a dcb and do lots of other things * */ static int test1() { DCB *dcb, *extra, *clone; int size = 100; int bite1 = 35; int bite2 = 60; int bite3 = 10; int buflen; /* Single buffer tests */ ss_dfprintf(stderr, "testdcb : creating buffer with type DCB_ROLE_SERVICE_LISTENER"); dcb = dcb_alloc(DCB_ROLE_SERVICE_LISTENER); printDCB(dcb); ss_info_dassert(dcb_isvalid(dcb), "New DCB must be valid"); ss_dfprintf(stderr, "\t..done\nAllocated dcb."); clone = dcb_clone(dcb); ss_dfprintf(stderr, "\t..done\nCloned dcb"); printAllDCBs(); ss_info_dassert(true, "Something is true"); ss_dfprintf(stderr, "\t..done\n"); dcb_close(dcb); ss_dfprintf(stderr, "Freed original dcb"); ss_info_dassert(!dcb_isvalid(dcb), "Freed DCB must not be valid"); ss_dfprintf(stderr, "\t..done\nMake clone DCB a zombie"); clone->state = DCB_STATE_NOPOLLING; dcb_close(clone); ss_info_dassert(dcb_get_zombies() == clone, "Clone DCB must be start of zombie list now"); ss_dfprintf(stderr, "\t..done\nProcess the zombies list"); dcb_process_zombies(0); ss_dfprintf(stderr, "\t..done\nCheck clone no longer valid"); ss_info_dassert(!dcb_isvalid(clone), "After zombie processing, clone DCB must not be valid"); ss_dfprintf(stderr, "\t..done\n"); return 0; }
/** * Link a session to a DCB. * * @param session The session to link with the dcb * @param dcb The DCB to be linked * @return True if the session was sucessfully linked to the DCB */ bool session_link_dcb(SESSION *session, DCB *dcb) { spinlock_acquire(&session->ses_lock); ss_info_dassert(session->state != SESSION_STATE_FREE, "If session->state is SESSION_STATE_FREE then this attempt to " "access freed memory block."); if (session->state == SESSION_STATE_FREE) { spinlock_release(&session->ses_lock); return false; } atomic_add(&session->refcount, 1); dcb->session = session; spinlock_release(&session->ses_lock); return true; }
/** * Allocate a new session for a new client of the specified service. * * Create the link to the router session by calling the newSession * entry point of the router using the router instance of the * service this session is part of. * * @param service The service this connection was established by * @param client_dcb The client side DCB * @return The newly created session or NULL if an error occured */ SESSION * session_alloc(SERVICE *service, DCB *client_dcb) { SESSION *session; session = (SESSION *)calloc(1, sizeof(SESSION)); ss_info_dassert(session != NULL, "Allocating memory for session failed."); if (session == NULL) { char errbuf[STRERROR_BUFLEN]; MXS_ERROR("Failed to allocate memory for " "session object due error %d, %s.", errno, strerror_r(errno, errbuf, sizeof(errbuf))); return NULL; } #if defined(SS_DEBUG) session->ses_chk_top = CHK_NUM_SESSION; session->ses_chk_tail = CHK_NUM_SESSION; #endif session->ses_is_child = (bool) DCB_IS_CLONE(client_dcb); spinlock_init(&session->ses_lock); session->service = service; session->client_dcb = client_dcb; session->n_filters = 0; memset(&session->stats, 0, sizeof(SESSION_STATS)); session->stats.connect = time(0); session->state = SESSION_STATE_ALLOC; /*< * Associate the session to the client DCB and set the reference count on * the session to indicate that there is a single reference to the * session. There is no need to protect this or use atomic add as the * session has not been made available to the other threads at this * point. */ session->refcount = 1; /*< * This indicates that session is ready to be shared with backend * DCBs. Note that this doesn't mean that router is initialized yet! */ session->state = SESSION_STATE_READY; /* * Only create a router session if we are not the listening * DCB or an internal DCB. Creating a router session may create a connection to a * backend server, depending upon the router module implementation * and should be avoided for the listener session * * Router session creation may create other DCBs that link to the * session, therefore it is important that the session lock is * relinquished before the router call. */ if (client_dcb->state != DCB_STATE_LISTENING && client_dcb->dcb_role != DCB_ROLE_INTERNAL) { session->router_session = service->router->newSession(service->router_instance, session); if (session->router_session == NULL) { session->state = SESSION_STATE_TO_BE_FREED; MXS_ERROR("Failed to create new router session for service '%s'. " "See previous errors for more details.", service->name); } /* * Pending filter chain being setup set the head of the chain to * be the router. As filters are inserted the current head will * be pushed to the filter and the head updated. * * NB This dictates that filters are created starting at the end * of the chain nearest the router working back to the client * protocol end of the chain. */ session->head.instance = service->router_instance; session->head.session = session->router_session; session->head.routeQuery = (void *)(service->router->routeQuery); session->tail.instance = session; session->tail.session = session; session->tail.clientReply = session_reply; if (SESSION_STATE_TO_BE_FREED != session->state && service->n_filters > 0 && !session_setup_filters(session)) { session->state = SESSION_STATE_TO_BE_FREED; MXS_ERROR("Setting up filters failed. " "Terminating session %s.", service->name); } } if (SESSION_STATE_TO_BE_FREED != session->state) { session->state = SESSION_STATE_ROUTER_READY; if (session->client_dcb->user == NULL) { MXS_INFO("Started session [%lu] for %s service ", session->ses_id, service->name); } else { MXS_INFO("Started %s client session [%lu] for '%s' from %s", service->name, session->ses_id, session->client_dcb->user, session->client_dcb->remote); } } else { MXS_INFO("Start %s client session [%lu] for '%s' from %s failed, will be " "closed as soon as all related DCBs have been closed.", service->name, session->ses_id, session->client_dcb->user, session->client_dcb->remote); } spinlock_acquire(&session_spin); /** Assign a session id and increase, insert session into list */ session->ses_id = ++session_id; session->next = allSessions; allSessions = session; spinlock_release(&session_spin); atomic_add(&service->stats.n_sessions, 1); atomic_add(&service->stats.n_current, 1); CHK_SESSION(session); client_dcb->session = session; return SESSION_STATE_TO_BE_FREED == session->state ? NULL : session; }
/** * test1 spinlock_acquire_nowait tests * * Test that spinlock_acquire_nowait returns false if the spinlock * is already taken. * * Test that spinlock_acquire_nowait returns true if the spinlock * is not taken. * * Test that spinlock_acquire_nowait does hold the spinlock. */ static bool do_hashtest( int argelems, int argsize) { bool succp = true; HASHTABLE* h; int nelems; int i; int* val_arr; int hsize; int longest; int* iter; ss_dfprintf(stderr, "testhash : creating hash table of size %d, including %d " "elements in total, at time %g.", argsize, argelems, (double)clock()-start); val_arr = (int *)malloc(sizeof(void *)*argelems); h = hashtable_alloc(argsize, hfun, cmpfun); ss_dfprintf(stderr, "\t..done\nAdd %d elements to hash table.", argelems); for (i=0; i<argelems; i++) { val_arr[i] = i; hashtable_add(h, (void *)&val_arr[i], (void *)&val_arr[i]); } if (argelems > 1000) ss_dfprintf(stderr, "\t..done\nOperation took %g", (double)clock()-start); ss_dfprintf(stderr, "\t..done\nRead hash table statistics."); hashtable_get_stats((void *)h, &hsize, &nelems, &longest); ss_dfprintf(stderr, "\t..done\nValidate read values."); ss_info_dassert(hsize == (argsize > 0 ? argsize: 1), "Invalid hash size"); ss_info_dassert((nelems == argelems) || (nelems == 0 && argsize == 0), "Invalid element count"); ss_info_dassert(longest <= nelems, "Too large longest list value"); if (argelems > 1000) ss_dfprintf(stderr, "\t..done\nOperation took %g", (double)clock()-start); ss_dfprintf(stderr, "\t..done\nValidate iterator."); HASHITERATOR *iterator = hashtable_iterator(h); read_lock(h); for (i=0; i < (argelems+1); i++) { iter = (int *)hashtable_next(iterator); if (iter == NULL) break; if (argelems < 100) ss_dfprintf(stderr, "\nNext item, iter = %d, i = %d", *iter, i); } read_unlock(h); ss_info_dassert((i == argelems) || (i == 0 && argsize == 0), "\nIncorrect number of elements from iterator"); hashtable_iterator_free(iterator); if (argelems > 1000) ss_dfprintf(stderr, "\t..done\nOperation took %g", (double)clock()-start); ss_dfprintf(stderr, "\t\t..done\n\nTest completed successfully.\n\n"); CHK_HASHTABLE(h); hashtable_free(h); free(val_arr); return succp; }
/** * Allocate a new session for a new client of the specified service. * * Create the link to the router session by calling the newSession * entry point of the router using the router instance of the * service this session is part of. * * @param service The service this connection was established by * @param client_dcb The client side DCB * @return The newly created session or NULL if an error occured */ SESSION * session_alloc(SERVICE *service, DCB *client_dcb) { SESSION *session; session = (SESSION *)calloc(1, sizeof(SESSION)); ss_info_dassert(session != NULL, "Allocating memory for session failed."); if (session == NULL) { int eno = errno; errno = 0; LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Error : Failed to allocate memory for " "session object due error %d, %s.", eno, strerror(eno)))); goto return_session; } #if defined(SS_DEBUG) session->ses_chk_top = CHK_NUM_SESSION; session->ses_chk_tail = CHK_NUM_SESSION; #endif spinlock_init(&session->ses_lock); /*< * Prevent backend threads from accessing before session is completely * initialized. */ spinlock_acquire(&session->ses_lock); session->service = service; session->client = client_dcb; session->n_filters = 0; memset(&session->stats, 0, sizeof(SESSION_STATS)); session->stats.connect = time(0); session->state = SESSION_STATE_ALLOC; /*< * Associate the session to the client DCB and set the reference count on * the session to indicate that there is a single reference to the * session. There is no need to protect this or use atomic add as the * session has not been made available to the other threads at this * point. */ session->data = client_dcb->data; client_dcb->session = session; session->refcount = 1; /*< * This indicates that session is ready to be shared with backend * DCBs. Note that this doesn't mean that router is initialized yet! */ session->state = SESSION_STATE_READY; /*< Release session lock */ spinlock_release(&session->ses_lock); /* * Only create a router session if we are not the listening * DCB or an internal DCB. Creating a router session may create a connection to a * backend server, depending upon the router module implementation * and should be avoided for the listener session * * Router session creation may create other DCBs that link to the * session, therefore it is important that the session lock is * relinquished beforethe router call. */ if (client_dcb->state != DCB_STATE_LISTENING && client_dcb->dcb_role != DCB_ROLE_INTERNAL) { session->router_session = service->router->newSession(service->router_instance, session); if (session->router_session == NULL) { /** * Inform other threads that session is closing. */ session->state = SESSION_STATE_STOPPING; /*< * Decrease refcount, set dcb's session pointer NULL * and set session pointer to NULL. */ session_free(session); client_dcb->session = NULL; session = NULL; LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Error : Failed to create %s session.", service->name))); goto return_session; } /* * Pending filter chain being setup set the head of the chain to * be the router. As filters are inserted the current head will * be pushed to the filter and the head updated. * * NB This dictates that filters are created starting at the end * of the chain nearest the router working back to the client * protocol end of the chain. */ session->head.instance = service->router_instance; session->head.session = session->router_session; session->head.routeQuery = (void *)(service->router->routeQuery); session->tail.instance = session; session->tail.session = session; session->tail.clientReply = session_reply; if (service->n_filters > 0) { if (!session_setup_filters(session)) { /** * Inform other threads that session is closing. */ session->state = SESSION_STATE_STOPPING; /*< * Decrease refcount, set dcb's session pointer NULL * and set session pointer to NULL. */ session_free(session); client_dcb->session = NULL; session = NULL; LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Error : Failed to create %s session.", service->name))); goto return_session; } } } spinlock_acquire(&session_spin); if (session->state != SESSION_STATE_READY) { session_free(session); client_dcb->session = NULL; session = NULL; LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Error : Failed to create %s session.", service->name))); spinlock_release(&session_spin); } else { session->state = SESSION_STATE_ROUTER_READY; session->next = allSessions; allSessions = session; spinlock_release(&session_spin); atomic_add(&service->stats.n_sessions, 1); atomic_add(&service->stats.n_current, 1); CHK_SESSION(session); } return_session: return session; }
/** * Add a DCB to the set of descriptors within the polling * environment. * * @param dcb The descriptor to add to the poll * @return -1 on error or 0 on success */ int poll_add_dcb(DCB *dcb) { int rc = -1; dcb_state_t old_state = DCB_STATE_UNDEFINED; dcb_state_t new_state; struct epoll_event ev; CHK_DCB(dcb); #ifdef EPOLLRDHUP ev.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLHUP | EPOLLET; #else ev.events = EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLET; #endif ev.data.ptr = dcb; /*< * Choose new state according to the role of dcb. */ if (dcb->dcb_role == DCB_ROLE_REQUEST_HANDLER) { new_state = DCB_STATE_POLLING; } else { ss_dassert(dcb->dcb_role == DCB_ROLE_SERVICE_LISTENER); new_state = DCB_STATE_LISTENING; } /*< * If dcb is in unexpected state, state change fails indicating that dcb * is not polling anymore. */ if (dcb_set_state(dcb, new_state, &old_state)) { rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dcb->fd, &ev); if (rc != 0) { int eno = errno; errno = 0; LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Error : Adding dcb %p in state %s " "to poll set failed. epoll_ctl failed due " "%d, %s.", dcb, STRDCBSTATE(dcb->state), eno, strerror(eno)))); } else { LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [poll_add_dcb] Added dcb %p in state %s to " "poll set.", pthread_self(), dcb, STRDCBSTATE(dcb->state)))); } ss_info_dassert(rc == 0, "Unable to add poll"); /*< trap in debug */ } else { LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Error : Unable to set new state for dcb %p " "in state %s. Adding to poll set failed.", dcb, STRDCBSTATE(dcb->state)))); } return rc; }