Ejemplo n.º 1
0
/*
 * perform some basic tests
 */
static	void	basic(table_t *tab_p)
{
  long	key;
  int	ret;
  void	*data_p;
  
  (void)printf("Performing basic tests:\n");
  (void)fflush(stdout);
  
  key = TEST_VALUE;
  ret = table_insert(tab_p, &key, sizeof(key), NULL, 0, &data_p, 0);
  if (ret != TABLE_ERROR_NONE) {
    (void)fprintf(stderr,
		  "could not store null pointer of size 0 in table: %s\n",
		 table_strerror(ret));
    exit(1);
  }
  
  /* try the replace */
  ret = table_insert(tab_p, &key, sizeof(key), NULL, 0, &data_p, 1);
  if (ret != TABLE_ERROR_NONE) {
    (void)fprintf(stderr,
		  "could not store null pointer of size 0 in table: %s\n",
		 table_strerror(ret));
    exit(1);
  }
  
  /* try to insert without replace */
  ret = table_insert(tab_p, &key, sizeof(key), NULL, 0, &data_p, 0);
  if (ret != TABLE_ERROR_OVERWRITE) {
    (void)printf("replaced a key in the table with no-overwrite flag: %s\n",
		 table_strerror(ret));
    exit(1);
  }
  
  /* delete the key */
  ret = table_delete(tab_p, &key, sizeof(key), NULL, NULL);
  if (ret != TABLE_ERROR_NONE) {
    (void)fprintf(stderr, "could not delete test key %ld: %s\n",
		  key, table_strerror(ret));
    exit(1);
  }
  
  /* test to make sure we can insert a NULL with size > 0 */
  ret = table_insert(tab_p, &key, sizeof(key), NULL, 100, &data_p, 0);
  if (ret != TABLE_ERROR_NONE) {
    (void)printf("could not add NULL with size > 0: %s\n",
		 table_strerror(ret));
    exit(1);
  }
  ret = table_delete(tab_p, &key, sizeof(key), NULL, NULL);
  if (ret != TABLE_ERROR_NONE) {
    (void)fprintf(stderr, "could not delete test key %ld: %s\n",
		  key, table_strerror(ret));
    exit(1);
  }
}
Ejemplo n.º 2
0
void
table_main(int ac, char **av)
{
	if (!strncmp(*av, "append", strlen(*av))) {
		table_append(ac, av);
	} else if (!strncmp(*av, "remove", strlen(*av))) {
		table_remove(ac, av);
	} else if (!strncmp(*av, "flush", strlen(*av))) {
		table_flush(ac, av);
	} else if (!strncmp(*av, "list", strlen(*av))) {
		table_list(ac, av);
	} else if (!strncmp(*av, "show", strlen(*av))) {
		table_show(ac, av);
	} else if (!strncmp(*av, "type", strlen(*av))) {
		table_create(ac, av);
	} else if (!strncmp(*av, "delete", strlen(*av))) {
		table_delete(ac, av);
	} else if (!strncmp(*av, "test", strlen(*av))) {
		table_test(ac,av);
	} else if (!strncmp(*av, "name", strlen(*av))) {
		table_rename(ac, av);
	} else {
		errx(EX_USAGE, "bad ipfw table command `%s'", *av);
	}
}
Ejemplo n.º 3
0
class_type make_class(class_type c, list_type resources, list_type classvars,
		      list_type properties, list_type messages)
{
   int has_constructor = False;

   c->resources = resources;
   c->classvars = list_append(st.override_classvars, classvars);
   c->properties = properties;

   /* Sort message handlers by id # */
   c->messages = SortMessageHandlerList(messages);

   /* Save away total # of properties in this class + parents */
   c->numproperties = st.maxproperties;

   /* Save away total # of class variables in this class + parents */
   c->numclassvars  = st.maxclassvars + 1;

   /* Clean out class variable table */
   table_delete(st.classvars);
   st.override_classvars = NULL;

   /* Erase constant list */
   st.constants = list_delete(st.constants);

   st.maxproperties = 0;  // Property #0 is reserved for SELF
   st.maxclassvars  = -1;

   return c;   
}
Ejemplo n.º 4
0
message_handler_type make_message_handler(message_header_type header, char *comment,
					  list_type locals, list_type stmts)
{
   message_handler_type h = (message_handler_type) SafeMalloc(sizeof(message_handler_struct));
   stmt_type stmt;

   /* Last statement of body must be PROPAGATE or RETURN */
   stmt = (stmt_type) list_last_item(stmts);

   if (stmt == NULL || (stmt->type != S_RETURN && stmt->type != S_PROP)) 
      action_error("Last statement must be PROPAGATE or RETURN");
   
   h->header  = header;
   h->locals  = locals;
   h->body    = stmts;
   if (comment == NULL)
      h->comment = NULL;
   else h->comment = make_string_constant(comment);

   /* Clean out local variable table.  We must do this at the end of 
    * each handler, since in make_message_header we have already checked
    * parameters names against old variables, which includes parameters
    * from the current function in the local table.
    */
   table_delete(st.localvars);
   st.maxlocals = -1; /* So that first local is numbered 0 */

   return h;
}
Ejemplo n.º 5
0
void ssl_scache_shmht_expire(server_rec *s)
{
    SSLModConfigRec *mc = myModConfig();
    SSLSrvConfigRec *sc = mySrvConfig(s);
    static time_t tLast = 0;
    table_linear_t iterator;
    time_t tExpiresAt;
    void *vpKey;
    void *vpKeyThis;
    void *vpData;
    int nKey;
    int nKeyThis;
    int nData;
    int nElements = 0;
    int nDeleted = 0;
    int bDelete;
    int rc;
    time_t tNow;

    /*
     * make sure the expiration for still not-accessed session
     * cache entries is done only from time to time
     */
    tNow = time(NULL);
    if (tNow < tLast+sc->nSessionCacheTimeout)
        return;
    tLast = tNow;

    ssl_mutex_on(s);
    if (table_first_r(mc->tSessionCacheDataTable, &iterator,
                      &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) {
        do {
            bDelete = FALSE;
            nElements++;
            if (nData < sizeof(time_t) || vpData == NULL)
                bDelete = TRUE;
            else {
                memcpy(&tExpiresAt, vpData, sizeof(time_t));
                if (tExpiresAt <= tNow)
                   bDelete = TRUE;
            }
            vpKeyThis = vpKey;
            nKeyThis  = nKey;
            rc = table_next_r(mc->tSessionCacheDataTable, &iterator,
                              &vpKey, &nKey, &vpData, &nData);
            if (bDelete) {
                table_delete(mc->tSessionCacheDataTable,
                             vpKeyThis, nKeyThis, NULL, NULL);
                nDeleted++;
            }
        } while (rc == TABLE_ERROR_NONE);
    }
    ssl_mutex_off(s);
    ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache (SHMHT) Expiry: "
            "old: %d, new: %d, removed: %d", nElements, nElements-nDeleted, nDeleted);
    return;
}
Ejemplo n.º 6
0
void close_inotify() {
  if (watches != NULL) {
    table_delete(watches);
  }

  if (inotify_fd >= 0) {
    close(inotify_fd);
  }
}
Ejemplo n.º 7
0
void ssl_scache_shmht_remove(server_rec *s, UCHAR *id, int idlen)
{
    SSLModConfigRec *mc = myModConfig();

    /* remove value under key in table */
    ssl_mutex_on(s);
    table_delete(mc->tSessionCacheDataTable, id, idlen, NULL, NULL);
    ssl_mutex_off(s);
    return;
}
Ejemplo n.º 8
0
/* bool delete_table(id, table_name) */
static int cc_delete_table(lua_State* L)
{
	int id;
	bool retcode;
	const char* table_name;
	database_handler_t* database_handler;
	worker_handler_t* handler = find_handler_by_stack(L);
	int args = lua_gettop(L);
	if (args < 2)
	{
		error_log("`%s` parameter lack:%d\n", __FUNCTION__, args);
		return 0;
	}

	if (!lua_isnumber(L, -args))
	{
		error_log("`%s` parameter error:%s\n", __FUNCTION__, lua_typename(L, lua_type(L, -args)));
		return 0;
	}

	if (!lua_isstring(L, -(args-1)))
	{
		error_log("`%s` parameter error:%s\n", __FUNCTION__, lua_typename(L, lua_type(L, -(args-1))));
		return 0;
	}

	id = lua_tointeger(L, -args);
	table_name = lua_tostring(L, -(args-1));
	database_handler = hash_table_find(handler->database_table, id);
	if (!database_handler)
	{
		error_log("`%s` not found database:%d\n", __FUNCTION__, id);
		return 0;
	}
	retcode = table_delete(database_handler, table_name);
	lua_pushboolean(L, retcode ? 1 : 0);

	return 1;
}
Ejemplo n.º 9
0
static CTL_MSG *
lookup_request (CTL_MSG * request,
		int (*comp) (table_t *, CTL_MSG *, time_t *))
{
  table_t *ptr;
  time_t now;

  time (&now);

  if (debug)
    print_request ("lookup_request", request);

  for (ptr = table; ptr; ptr = ptr->next)
    {
      if (debug)
	print_request ("comparing against: ", &ptr->request);

      if ((ptr->time - now) > max_request_ttl)
	{
	  /* the entry is too old */
	  if (debug)
	    print_request ("deleting expired entry", &ptr->request);
	  table_delete (ptr);
	}
      else
	{
	  if (comp (ptr, request, &now) == 0)
	    {
	      if (debug)
		print_request ("found", &ptr->request);
	      return &ptr->request;
	    }
	}
    }
  if (debug)
    syslog (LOG_DEBUG, "not found");
  return NULL;
}
Ejemplo n.º 10
0
/*
 * simple_table_delete - delete a tuple
 *
 * This routine may be used to delete a tuple when concurrent updates of
 * the target tuple are not expected (for example, because we have a lock
 * on the relation associated with the tuple).  Any failure is reported
 * via ereport().
 */
void
simple_table_delete(Relation rel, ItemPointer tid, Snapshot snapshot)
{
	TM_Result	result;
	TM_FailureData tmfd;

	result = table_delete(rel, tid,
						  GetCurrentCommandId(true),
						  snapshot, InvalidSnapshot,
						  true /* wait for commit */ ,
						  &tmfd, false /* changingPart */ );

	switch (result)
	{
		case TM_SelfModified:
			/* Tuple was already updated in current command? */
			elog(ERROR, "tuple already updated by self");
			break;

		case TM_Ok:
			/* done successfully */
			break;

		case TM_Updated:
			elog(ERROR, "tuple concurrently updated");
			break;

		case TM_Deleted:
			elog(ERROR, "tuple concurrently deleted");
			break;

		default:
			elog(ERROR, "unrecognized table_delete status: %u", result);
			break;
	}
}
Ejemplo n.º 11
0
/*
 * try ITERN random program iterations.
 */
static	void	stress(table_t *tab_p, const int iter_n, const int mmaping_b)
{
  void		*data, *key;
  int		which = 0, mode, weight_total;
  int		iter_c, pnt_c, free_c, ret, ksize, dsize;
  entry_t	*grid, *free_p, *grid_p, *last_p;
  int		linear_b = 0, linear_eof_b = 0;
  
  (void)printf("Performing stress tests with %d iterations:\n", iter_n);
  (void)fflush(stdout);
  
  grid = malloc(sizeof(entry_t) * MAX_ENTRIES);
  if (grid == NULL) {
    (void)printf("problems allocating space for %d entries.\n",
		 MAX_ENTRIES);
    exit(1);
  }
  
  /* initialize free list */
  free_p = grid;
  for (grid_p = grid; grid_p < grid + MAX_ENTRIES; grid_p++) {
    grid_p->en_free_b = 1;
    grid_p->en_key = NULL;
    grid_p->en_key_size = 0;
    grid_p->en_data = NULL;
    grid_p->en_data_size = 0;
    grid_p->en_next_p = grid_p + 1;
  }
  /* redo the last next pointer */
  (grid_p - 1)->en_next_p = NULL;
  free_c = MAX_ENTRIES;
  
#if 0
  /* load the list */
  if (mmaping_b) {
    for (ret = table_first(tab_p, (void **)&key_p, NULL, (void **)&data_p,
			   NULL);
	 ret == TABLE_ERROR_NONE;
	 ret = table_next(tab_p, (void **)&key_p, NULL, (void **)&data_p,
			  NULL)) {
    }
  }
#endif
  
  /* total the weights */
  weight_total = 0;
  for (mode = 0; mode < MODE_MAX; mode++) {
    weight_total += mode_weights[mode];
  }
  
  for (iter_c = 0; iter_c < iter_n;) {
    int		weight;
    
    /* decide what to do */
    weight = RANDOM_VALUE(weight_total) + 1;
    for (mode = 0; mode < MODE_MAX; mode++) {
      weight -= mode_weights[mode];
      if (weight <= 0) {
	break;
      }
    }
    
    /* out of bounds */
    if (mode >= MODE_MAX) {
      continue;
    }
    
    switch (mode) {
      
    case MODE_CLEAR:
      if (mmaping_b || large_b) {
	continue;
      }
      
      call_c++;
      table_clear(tab_p);
      
      /* re-init free list */
      free_p = grid;
      for (grid_p = grid; grid_p < grid + MAX_ENTRIES; grid_p++) {
	if (! grid_p->en_free_b) {
	  if (grid_p->en_key != NULL) {
	    free(grid_p->en_key);
	  }
	  if (grid_p->en_data != NULL) {
	    free(grid_p->en_data);
	  }
	}
	grid_p->en_free_b = 1;
	grid_p->en_next_p = grid_p + 1;
      }
      /* redo the last next pointer */
      (grid_p - 1)->en_next_p = NULL;
      free_c = MAX_ENTRIES;
      linear_b = 0;
      linear_eof_b = 0;
      iter_c++;
      if (verbose_b) {
	(void)printf("table cleared.\n");
	fflush(stdout);
      }
      break;
      
    case MODE_INSERT:
      if (mmaping_b) {
	continue;
      }
      if (free_c > 0) {
	which = RANDOM_VALUE(free_c);
	last_p = NULL;
	grid_p = free_p;
	for (pnt_c = 0; pnt_c < which && grid_p != NULL; pnt_c++) {
	  last_p = grid_p;
	  grid_p = grid_p->en_next_p;
	}
	if (grid_p == NULL) {
	  (void)printf("reached end of free list prematurely\n");
	  exit(1);
	}
	
	do {
	  key = random_block(&ksize);
	} while (key == NULL);
	data = random_block(&dsize);
	
	call_c++;
	ret = table_insert(tab_p, key, ksize, data, dsize, NULL, 0);
	if (ret == TABLE_ERROR_NONE) {
	  if (verbose_b) {
	    (void)printf("stored in pos %d: %d, %d bytes of key, data\n",
			 grid_p - grid, ksize, dsize);
	    fflush(stdout);
	  }
	  
	  grid_p->en_free_b = 0;
	  grid_p->en_key = key;
	  grid_p->en_key_size = ksize;
	  grid_p->en_data = data;
	  grid_p->en_data_size = dsize;
	  
	  /* shift free list */
	  if (last_p == NULL) {
	    free_p = grid_p->en_next_p;
	  }
	  else {
	    last_p->en_next_p = grid_p->en_next_p;
	  }
	  grid_p->en_next_p = NULL;
	  free_c--;
	  iter_c++;
	}
	else {
	  for (grid_p = grid; grid_p < grid + MAX_ENTRIES; grid_p++) {
	    if (grid_p->en_free_b) {
	      continue;
	    }
	    if (grid_p->en_key_size == ksize
		&& memcmp(grid_p->en_key, key, ksize) == 0) {
	      break;
	    }
	  }
	  
	  /* if we did not store it then error */
	  if (grid_p >= grid + MAX_ENTRIES) {
	    (void)fprintf(stderr, "ERROR storing #%d: %s\n",
			  which, table_strerror(ret));
	  }
	  if (key != NULL) {
	    free(key);
	  }
	  if (data != NULL) {
	    free(data);
	  }
	}
      }
      break;
      
    case MODE_OVERWRITE:
      if (mmaping_b) {
	continue;
      }
      if (free_c < MAX_ENTRIES) {
	which = RANDOM_VALUE(MAX_ENTRIES);
	
	if (grid[which].en_free_b) {
	  continue;
	}
	
	data = random_block(&dsize);
	
	call_c++;
	ret = table_insert(tab_p, grid[which].en_key, grid[which].en_key_size,
			   data, dsize, NULL, 1);
	if (ret == TABLE_ERROR_NONE) {
	  if (verbose_b) {
	    (void)printf("overwrite pos %d with data of %d bytes\n",
			 which, dsize);
	    fflush(stdout);
	  }
	  grid[which].en_free_b = 0;
	  if (grid[which].en_data != NULL) {
	    free(grid[which].en_data);
	  }
	  grid[which].en_data = data;
	  grid[which].en_data_size = dsize;
	  grid[which].en_next_p = NULL;
	  free_c--;
	  iter_c++;
	}
	else {
	  (void)fprintf(stderr, "ERROR overwriting #%d: %s\n",
			which, table_strerror(ret));
	  free(data);
	}
      }
      break;
      
    case MODE_RETRIEVE:
      if (free_c < MAX_ENTRIES) {
	which = RANDOM_VALUE(MAX_ENTRIES);
	
	if (grid[which].en_free_b) {
	  continue;
	}
	
	call_c++;
	ret = table_retrieve(tab_p, grid[which].en_key, grid[which].en_key_size,
			     (void **)&data, &dsize);
	if (ret == TABLE_ERROR_NONE) {
	  if (grid[which].en_data_size == dsize
	      && memcmp(grid[which].en_data, data, dsize) == 0) {
	    if (verbose_b) {
	      (void)printf("retrieved key #%d, got data of %d bytes\n",
			   which, dsize);
	      fflush(stdout);
	    }
	  }
	  else {
	    (void)fprintf(stderr,
			  "ERROR: retrieve key #%d: data (%d bytes) didn't "
			  "match table (%d bytes)\n",
			  which, grid[which].en_data_size, dsize);
	  }
	  iter_c++;
	}
	else {
	  (void)fprintf(stderr, "error retrieving key #%d: %s\n",
			which, table_strerror(ret));
	}
      }
      break;
      
    case MODE_DELETE:
      if (mmaping_b) {
	continue;
      }
      if (free_c >= MAX_ENTRIES) {
	continue;
      }
      
      which = RANDOM_VALUE(MAX_ENTRIES);
      
      if (grid[which].en_free_b) {
	continue;
      }
      
      call_c++;
      ret = table_delete(tab_p, grid[which].en_key, grid[which].en_key_size,
			 (void **)&data, &dsize);
      if (ret == TABLE_ERROR_NONE) {
	if (grid[which].en_data_size == dsize
	    && memcmp(grid[which].en_data, data, dsize) == 0) {
	  if (verbose_b) {
	    (void)printf("deleted key #%d, got data of %d bytes\n",
			 which, dsize);
	    fflush(stdout);
	  }
	}
	else {
	  (void)fprintf(stderr,
			"ERROR deleting key #%d: data didn't match table\n",
			which);
	}
	grid[which].en_free_b = 1;
	if (grid[which].en_key != NULL) {
	  free(grid[which].en_key);
	}
	if (grid[which].en_data != NULL) {
	  free(grid[which].en_data);
	}
	grid[which].en_next_p = free_p;
	free_p = grid + which;
	free_c++;
	if (free_c == MAX_ENTRIES) {
	  linear_b = 0;
	  linear_eof_b = 0;
	}
	iter_c++;
	if (data != NULL) {
	  free(data);
	}
      }
      else {
	(void)fprintf(stderr, "ERROR deleting key %d: %s\n",
		      which, table_strerror(ret));
      }
      break;
      
    case MODE_DELETE_FIRST:
      /*
       * We have a problem here.  This is the only action routine
       * which modifies the table and is not key based.  We don't have
       * a way of looking up the key in our local data structure.
       */
      break;
      
    case MODE_FIRST:
      call_c++;
      ret = table_first(tab_p, (void **)&key, &ksize, (void **)&data, &dsize);
      if (ret == TABLE_ERROR_NONE) {
	linear_b = 1;
	linear_eof_b = 0;
	if (verbose_b) {
	  (void)printf("first entry has key, data of %d, %d bytes\n",
		       ksize, dsize);
	  fflush(stdout);
	}
	iter_c++;
      }
      else if (free_c == MAX_ENTRIES) {
	if (verbose_b) {
	  (void)printf("no first in table\n");
	  fflush(stdout);
	}
      }
      else {
	(void)fprintf(stderr, "ERROR: first in table: %s\n",
		      table_strerror(ret));
      }
      break;
      
    case MODE_NEXT:
      call_c++;
      ret = table_next(tab_p, (void **)&key, &ksize, (void **)&data, &dsize);
      if (ret == TABLE_ERROR_NONE) {
	if (verbose_b) {
	  (void)printf("next entry has key, data of %d, %d\n",
		       ksize, dsize);
	  fflush(stdout);
	}
	iter_c++;
      }
      else if (ret == TABLE_ERROR_LINEAR && (! linear_b)) {
	if (verbose_b) {
	  (void)printf("no first command run yet\n");
	  fflush(stdout);
	}
      }
      else if (ret == TABLE_ERROR_NOT_FOUND) {
	if (verbose_b) {
	  (void)printf("reached EOF with next in table: %s\n",
		       table_strerror(ret));
	  fflush(stdout);
	}
	linear_b = 0;
	linear_eof_b = 1;
      }
      else {
	(void)fprintf(stderr, "ERROR: table_next reports: %s\n",
		      table_strerror(ret));
	linear_b = 0;
	linear_eof_b = 0;
      }
      break;
      
    case MODE_THIS:
      call_c++;
      ret = table_this(tab_p, (void **)&key, &ksize, (void **)&data, &dsize);
      if (ret == TABLE_ERROR_NONE) {
	if (verbose_b) {
	  (void)printf("this entry has key,data of %d, %d bytes\n",
		       ksize, dsize);
	  fflush(stdout);
	}
	iter_c++;
      }
      else if (ret == TABLE_ERROR_LINEAR && (! linear_b)) {
	if (verbose_b) {
	  (void)printf("no first command run yet\n");
	  fflush(stdout);
	}
      }
      else if (ret == TABLE_ERROR_NOT_FOUND || linear_eof_b) {
	if (verbose_b) {
	  (void)printf("table linear already reached EOF\n");
	  fflush(stdout);
	}
      }
      else {
	(void)fprintf(stderr, "ERROR: this table: %s\n", table_strerror(ret));
	linear_b = 0;
	linear_eof_b = 0;
      }
      break;
      
    case MODE_INFO:
      {
	int	buckets, entries;
	
	call_c++;
	ret = table_info(tab_p, &buckets, &entries);
	if (ret == TABLE_ERROR_NONE) {
	  if (verbose_b) {
	    (void)printf("table has %d buckets, %d entries\n",
			 buckets, entries);
	    fflush(stdout);
	  }
	  iter_c++;
	}
	else {
	  (void)fprintf(stderr, "ERROR: table info: %s\n",
			table_strerror(ret));
	}
      }
    break;
    
    case MODE_ADJUST:
      {
	int	buckets, entries;
	
	if (mmaping_b || auto_adjust_b || large_b) {
	  continue;
	}
	
	call_c++;
	ret = table_info(tab_p, &buckets, &entries);
	if (ret == TABLE_ERROR_NONE) {
	  if (entries == 0) {
	    if (verbose_b) {
	      (void)printf("cannot adjusted table, %d entries\n", entries);
	      fflush(stdout);
	    }
	  }
	  else if (buckets == entries) {
	    if (verbose_b) {
	      (void)printf("no need to adjust table, %d buckets and entries\n",
			   buckets);
	      fflush(stdout);
	    }
	  }
	  else {
	    ret = table_adjust(tab_p, entries);
	    if (ret == TABLE_ERROR_NONE) {
	      (void)printf("adjusted table from %d to %d buckets\n",
			   buckets, entries);
	      iter_c++;
	    }
	    else {
	      (void)printf("ERROR: table adjust to %d buckets: %s\n",
			   entries, table_strerror(ret));
	    }
	  }
	}
	else {
	  (void)fprintf(stderr, "ERROR: table info: %s\n",
			table_strerror(ret));
	}
      }
      break;
      
    default:
      (void)printf("unknown mode %d\n", which);
      break;
    }
  }
  
  /* run through the grid and free the entries */
  for (grid_p = grid; grid_p < grid + MAX_ENTRIES; grid_p++) {
    if (! grid_p->en_free_b) {
      if (grid_p->en_key != NULL) {
	free(grid_p->en_key);
      }
      if (grid_p->en_data != NULL) {
	free(grid_p->en_data);
      }
    }
  }
  
  /* free used pointers */
  free(grid);
}
Ejemplo n.º 12
0
    mysql::Binary_log_event *process_event(mysql::Binary_log_event *event) {

        if (event->get_event_type() != mysql::USER_DEFINED)
            return event;

        std::cout << "Replay: Event type: [" << mysql::system::get_event_type_str(event->get_event_type())
        << "] length: " << event->header()->event_length
        << " next pos: " << event->header()->next_position
        << std::endl;

        mysql::Transaction_log_event *trans = static_cast<mysql::Transaction_log_event *>(event);
        int row_count = 0;
        /*
          The transaction event we created has aggregated all row events in an
          ordered list.
        */
        std::list<Binary_log_event *>::iterator it = (trans->m_events).begin();
        mysql::Binary_log_event *event1;
        for (; it != (trans->m_events).end(); ++it) {
            event1 = *it;
            std::cout << "transaction log event!! [" << event->get_event_type() << "], binlogev_type ["
                                                                                << event1->get_event_type() << "]\n";
            switch (event1->get_event_type()) {
                case mysql::WRITE_ROWS_EVENT:
                case mysql::WRITE_ROWS_EVENT_V1:
                case mysql::DELETE_ROWS_EVENT:
                case mysql::DELETE_ROWS_EVENT_V1:
                case mysql::UPDATE_ROWS_EVENT:
                case mysql::UPDATE_ROWS_EVENT_V1:
                    std::cout << "transaction log event[write/delete/update]!!\n";
                    mysql::Row_event *rev = static_cast<mysql::Row_event *>(event1);
                    uint64_t table_id = rev->table_id;

                    Int_to_Event_map::iterator tm_it = trans->table_map().find(table_id);
                    if (tm_it != trans->table_map().end()) {
                        std::cout << "transaction log event!![TABLE_ID FOUND]\n";

                        Binary_log_event *tmevent = tm_it->second;
                        assert(tmevent != NULL);
                        mysql::Table_map_event *tm = static_cast<mysql::Table_map_event *>(tmevent);
                        /*
                         Each row event contains multiple rows and fields. The Row_iterator
                         allows us to iterate one row at a time.
                        */
                        mysql::Row_event_set rows(rev, tm);
                        /*
                         Create a fully qualified table name
                        */
                        std::ostringstream os;
                        os << tm->db_name << '.' << tm->table_name;
                        std::cout << "transaction log event!![TABLE is " << os.str() << "]\n";
                        try {
                            mysql::Row_event_set::iterator it = rows.begin();
                            std::cout << "transaction log event!![after rows.begin]\n";
                            do {
                                mysql::Row_of_fields fields = *it;

                                if (event1->get_event_type() == mysql::WRITE_ROWS_EVENT ||
                                    event1->get_event_type() == mysql::WRITE_ROWS_EVENT_V1) {
                                    std::cout << "transaction log event!![WRITE]\n";
                                    table_insert(os.str(), fields);
                                }

                                if (event1->get_event_type() == mysql::UPDATE_ROWS_EVENT ||
                                    event1->get_event_type() == mysql::UPDATE_ROWS_EVENT_V1) {
                                    ++it;
                                    mysql::Row_of_fields fields2 = *it;
                                    std::cout << "transaction log event!![UPDATE]\n";
                                    table_update(os.str(), fields, fields2);
                                }

                                if (event1->get_event_type() == mysql::DELETE_ROWS_EVENT ||
                                    event1->get_event_type() == mysql::DELETE_ROWS_EVENT_V1) {
                                    std::cout << "transaction log event!![DELETE]\n";

                                    table_delete(os.str(), fields);
                                }
                            } while (++it != rows.end());
                        }
                        catch (const std::logic_error &le) {
                            std::cout << "MySQL Data Type error: " << le.what() << '\n';
                        }
                        catch (std::exception const& ex) {
                            std::cout << "transaction log event error: " << ex.what() << "\n";
                        }
                    }
                    else {
                        std::cout << "Table id " << table_id
                        << " was not registered by any preceding table map event."
                        << std::endl;
                        continue;
                    }

            }
        }
        /* Consume the event */
        delete trans;

        return 0;
    }
Ejemplo n.º 13
0
int main (int argc, char **argv)
{
  Table *tab;
  int ii, jj;
  Alignment *sol;
  int nsol = 1;
  int done;
  
  if (argc < 3)
    errx (EXIT_FAILURE, "please provide two strings on the command line, for example 'vbr yog'");
  tab = table_new (argv[1], argv[2]);
  
  printf ("input source:      %s\n"
	  "input destination: %s\n",
	  argv[1], argv[2]);
  
  /***************************************************
   * propagate
   */
  
  for (ii = 1; ii <= tab->srclen; ++ii) {
    for (jj = 1; jj <= tab->dstlen; ++jj) {
      int best;
      char * act;
      
      tab->state[ii][jj].v_ins = tab->state[ii][jj-1].v_best + GAP_COST;
      best = tab->state[ii][jj].v_ins;
      
      tab->state[ii][jj].v_del = tab->state[ii-1][jj].v_best + GAP_COST;
      if (best < tab->state[ii][jj].v_del)
	best = tab->state[ii][jj].v_del;
      
      tab->state[ii][jj].v_match
	= tab->state[ii-1][jj-1].v_best
	+ match_cost (tab->src[ii-1], /* use ii-1 because of the extra "gap" at the beginning */
		      tab->dst[jj-1]);
      if (best < tab->state[ii][jj].v_match)
	best = tab->state[ii][jj].v_match;
      
      act = tab->state[ii][jj].act;
      if (best == tab->state[ii][jj].v_match)
	*(act++) = 'm';
      if (best == tab->state[ii][jj].v_del)
	*(act++) = 'd';
      if (best == tab->state[ii][jj].v_ins)
	*(act++) = 'i';
      *(act++) = '\0';
      
      tab->state[ii][jj].v_best = best;
    }
  }
  
  /***************************************************
   * print
   */
  
  printf ("\n    _");
  for (ii = 1; ii <= tab->dstlen; ++ii)
    printf ("    %c", tab->dst[ii-1]);
  printf ("\n\n");
  for (ii = 0; ii <= tab->srclen; ++ii) {
    printf ("%c", ii == 0 ? '_' : tab->src[ii-1]);
    for (jj = 0; jj <= tab->dstlen; ++jj)
      printf (" % 4d", tab->state[ii][jj].v_best);
    printf ("\n ");
    for (jj = 0; jj <= tab->dstlen; ++jj)
      printf (" %4s", tab->state[ii][jj].act);
    printf ("\n\n");
  }
  
  /***************************************************
   * trace back
   */
  
  sol = alignment_new (tab);
  
  for (done = 0; done != 1; /**/) {
    int ncheck;
    done = 1;
    
    /*
      check for branches, but may end up appending duplicates which
      should not be checked this time around... so remember the old
      size in ncheck
    */
    ncheck = nsol;
    for (ii = 0; ii < ncheck; ++ii) {
      
      /*
	skip finished alignments
      */
      if (sol[ii].isrc == 0 && sol[ii].idst == 0)
	continue;
      
      /*
	check whether we have a 2nd and a 3rd action
      */
      for (jj = 1; jj <= 2; ++jj) {
	
	/*
	  no more actions when we hit the '\0' of the action string
	*/
	if (tab->state[sol[ii].isrc][sol[ii].idst].act[jj] == '\0')
	  break;
	
	/*
	  append a duplicate of sol[ii] that uses jj as iact
	*/
	if (NULL == (sol = realloc (sol, (nsol + 1) * sizeof *sol)))
	  err (EXIT_FAILURE, "realloc sol");
	alignment_dup (sol + nsol, sol + ii, jj);
	
	++nsol;
      }
    }
    
    /*
      update all alignment branches
    */
    for (ii = 0; ii < nsol; ++ii) {
      char act;
      
      /*
	skip finished alignments
      */
      if (sol[ii].isrc == 0 && sol[ii].idst == 0)
	continue;
      
      /*
	perform next action in the backtrace
      */
      done = 0;
      act = tab->state[sol[ii].isrc][sol[ii].idst].act[sol[ii].iact];
      if ('m' == act) {
	*(--sol[ii].src) = tab->src[--sol[ii].isrc];
	*(--sol[ii].dst) = tab->dst[--sol[ii].idst];
      }
      else if ('i' == act) {
	*(--sol[ii].src) = '_';
	*(--sol[ii].dst) = tab->dst[--sol[ii].idst];
      }
      else if ('d' == act) {
	*(--sol[ii].src) = tab->src[--sol[ii].isrc];
	*(--sol[ii].dst) = '_';
      }
      else
	errx (EXIT_FAILURE, "BUG: action %d  solution %d  isrc %d  idst %d  iact %d",
	      (int) act, ii, sol[ii].isrc, sol[ii].idst, sol[ii].iact);
      
      /*
	reset iact to zero (only becomes non-zero in the branch detection)
      */
      sol[ii].iact = 0;
    }
  }
  
  /*
    print all optimal alignments
  */
  printf ("backtrace:\n\n");
  for (ii = 0; ii < nsol; ++ii)
    printf ("output source:      %s\n"
	    "output destination: %s\n\n",
	    sol[ii].src, sol[ii].dst);
  
  /***************************************************
   * clean up after ourselves
   */
  
  for (ii = 0; ii < nsol; ++ii) {
    free (sol[ii].srcbuf);
    free (sol[ii].dstbuf);
  }
  free (sol);
  table_delete (tab);
  
  return 0;
}
Ejemplo n.º 14
0
int main (int argc, char **argv)
{
  Table *tab;
  int ii, jj;
  
  if (argc < 3)
    errx (EXIT_FAILURE, "please provide two strings on the command line");
  tab = table_new (argv[1], argv[2]);
  
  printf ("input source:      %s\n"
	  "input destination: %s\n",
	  argv[1], argv[2]);
  
  /***************************************************
   * propagate
   */
  
  for (ii = 1; ii <= tab->srclen; ++ii) {
    for (jj = 1; jj <= tab->dstlen; ++jj) {
      int best;
      char * act;
      
      tab->state[ii][jj].v_ins = tab->state[ii][jj-1].v_best + GAP_COST;
      best = tab->state[ii][jj].v_ins;
      
      tab->state[ii][jj].v_del = tab->state[ii-1][jj].v_best + GAP_COST;
      if (best < tab->state[ii][jj].v_del)
	best = tab->state[ii][jj].v_del;
      
      tab->state[ii][jj].v_match
	= tab->state[ii-1][jj-1].v_best
	+ match_cost (tab->src[ii-1], /* use ii-1 because of the extra "gap" at the beginning */
		      tab->dst[jj-1]);
      if (best < tab->state[ii][jj].v_match)
	best = tab->state[ii][jj].v_match;
      
      if (best < 0)
	best = 0;
      
      act = tab->state[ii][jj].act;
      if (best == tab->state[ii][jj].v_match)
	*(act++) = 'm';
      if (best == tab->state[ii][jj].v_del)
	*(act++) = 'd';
      if (best == tab->state[ii][jj].v_ins)
	*(act++) = 'i';
      *(act++) = '\0';
      
      tab->state[ii][jj].v_best = best;
    }
  }
  
  /***************************************************
   * print
   */
  
  printf ("\n    _");
  for (ii = 1; ii <= tab->dstlen; ++ii)
    printf ("    %c", tab->dst[ii-1]);
  printf ("\n\n");
  for (ii = 0; ii <= tab->srclen; ++ii) {
    printf ("%c", ii == 0 ? '_' : tab->src[ii-1]);
    for (jj = 0; jj <= tab->dstlen; ++jj)
      printf (" % 4d", tab->state[ii][jj].v_best);
    printf ("\n ");
    for (jj = 0; jj <= tab->dstlen; ++jj)
      printf (" %4s", tab->state[ii][jj].act);
    printf ("\n\n");
  }
  
  /***************************************************
   * trace back is not so easy with Smith-Waterman, will skip it for
   * now
   */
  
  /***************************************************
   * clean up after ourselves
   */
  
  table_delete (tab);
  
  return 0;
}
Ejemplo n.º 15
0
/* driver to test sequence of inserts and deletes.
*/
void equilibriumDriver(void)
{
    int i, code;
    int key_range, num_keys;
    int size;
    int ran_index;
    int suc_search, suc_trials, unsuc_search, unsuc_trials;
    int keys_added, keys_removed;
    int *ip;
    table_t *test_table;
    hashkey_t key;
    data_t dp;
    clock_t start, end;

    /* print parameters for this test run */
    printf("\n----- Equilibrium test driver -----\n");
    printf("  Trials: %d\n", Trials);

    test_table = table_construct(TableSize, ProbeDec);
    num_keys = (int) (TableSize * LoadFactor);

    /* build a table as starting point */
    build_table(test_table, num_keys);
    size = num_keys;

    key_range = MAXID - MINID + 1;
    /* in equilibrium make inserts and removes with equal probability */
    suc_search = suc_trials = unsuc_search = unsuc_trials = 0;
    keys_added = keys_removed = 0;
    start = clock();
    for (i = 0; i < Trials; i++) {
        if (drand48() < 0.5 && table_full(test_table) == FALSE) {
            // insert only if table not full
            // for separate chaining table is never full
            key = (hashkey_t) (drand48() * key_range) + MINID;
            ip = (int *) malloc(sizeof(int));
            *ip = key;
            /* insert returns 0 if key not found, 1 if older key found */
            if (Verbose) printf("Trial %d, Insert Key %u", i, key);
            code = table_insert(test_table, key, ip);
            if (code == 0) {
                /* key was not in table so added */
                unsuc_search += table_stats(test_table);
                unsuc_trials++;
                keys_added++;
                if (Verbose) printf(" added\n");
            } else if (code == 1) {
                suc_search += table_stats(test_table);
                suc_trials++;
                if (Verbose) printf(" replaced (rare!)\n");
            } else {
                printf("!!!Trial %d failed to insert key (%u) with code (%d)\n", i, key, code);
                exit(10);
            }
        } else if (table_entries(test_table) > TableSize/4) {
            // delete only if table is at least 25% full
            // why 25%?  Would 10% be better?  Lower than 10% will
            // be computationally expensive
            do {
                ran_index = (int) (drand48() * TableSize);
                key = table_peek(test_table, ran_index,0);
            } while (key == 0);
            if (Verbose) printf("Trial %d, Delete Key %u", i, key);
            if (key < MINID || MAXID < key) {
                printf("\n\n  table peek failed: invalid key (%u) during trial (%d)\n", key, i);
                exit(12);
            }
            dp = table_delete(test_table, key);
            if (dp != NULL) {
                if (Verbose) printf(" removed\n");
                suc_search += table_stats(test_table);
                suc_trials++;
                keys_removed++;
                assert(*(int *)dp == key);
                free(dp);
            } else {
                printf("!!! failed to find key (%u) in table, trial (%d)!\n", key, i);
                printf("this is a catastrophic error!!!\n");
                exit(11);
            }
        }
    }
    end = clock();

    if (Verbose) {
        printf("Table after equilibrium trials\n");
        table_debug_print(test_table);
    }

    size += keys_added - keys_removed;
    printf("  Keys added (%d), removed (%d) new size should be (%d) and is (%d)\n",
           keys_added, keys_removed, size, table_entries(test_table));
    assert(size == table_entries(test_table));
    printf("  After exercise, time=%g \n",
           1000*((double)(end-start))/CLOCKS_PER_SEC);
    printf("  successful searches during exercise=%g, trials=%d\n",
           (double) suc_search/suc_trials, suc_trials);
    printf("  unsuccessful searches during exercise=%g, trials=%d\n",
           (double) unsuc_search/unsuc_trials, unsuc_trials);


    /* test access times for new table */

    /* separate chaining handled differently
     * should improve design of table_peek function so it
     * returns 0 if count is invalid when using open addressing.
     * In current design it is ignored
     */
    suc_search = suc_trials = unsuc_search = unsuc_trials = 0;
    start = clock();
    /* check each position in table for key */
    if (ProbeDec == CHAIN) {
        for (i = 0; i < TableSize; i++) {
            int count = 0;
            key = table_peek(test_table, i, count);
            while (key != 0) {
                assert(MINID <= key && key <= MAXID);
                dp = table_retrieve(test_table, key);
                if (dp == NULL) {
                    printf("Failed key (%u) should be at (%d)\n", key, i);
                    exit(15);
                } else {
                    suc_search += table_stats(test_table);
                    suc_trials++;
                    assert(*(int *)dp == key);
                }
                key = table_peek(test_table, i, ++count);
            }
        }
    } else {
        for (i = 0; i < TableSize; i++) {
            key = table_peek(test_table, i, 0);
            if (key != 0) {
                assert(MINID <= key && key <= MAXID);
                dp = table_retrieve(test_table, key);
                if (dp == NULL) {
                    printf("Failed to find key (%u) but it is in location (%d)\n",
                           key, i);
                    exit(16);
                } else {
                    suc_search += table_stats(test_table);
                    suc_trials++;
                    assert(*(int *)dp == key);
                }
            }
        }
    }
    for (i = 0; i < Trials; i++) {
        /* random key with uniform distribution */
        key = (hashkey_t) (drand48() * key_range) + MINID;
        dp = table_retrieve(test_table, key);
        if (dp == NULL) {
            unsuc_search += table_stats(test_table);
            unsuc_trials++;
        } else {
            // this should be very rare
            assert(*(int *)dp == key);
        }
    }
    end = clock();
    size = table_entries(test_table);
    printf("  After retrieve experiment, time=%g\n",
           1000*((double)(end-start))/CLOCKS_PER_SEC);
    printf("  New load factor = %g\n", (double) size/TableSize);
    printf("  Percent empty locations marked deleted = %g\n",
           (double) 100.0 * table_deletekeys(test_table)
           / (TableSize - table_entries(test_table)));

    printf("   Measured avg probes for successful search=%g, trials=%d\n",
           (double) suc_search/suc_trials, suc_trials);

    if (ProbeDec == CHAIN && LoadFactor > 0.5  && LoadFactor < 1.5) {
        printf("     ** This measure is biased.  See comments\n\n");
        /* The design of the equilibirum driver depends on the uniform
         * selection of keys to insert and remove.  For linear, double, and
         * quadratic probing selecting a key to remove is done with a uniform
         * distribution among all possible keys.  However, for separate
         * chaining, the algorithm simply picks a table location with a uniform
         * distribution, but this is not the same as picking a key with a
         * uniform distribution.  So, there is a bias that a key in a table
         * location with fewer other keys is more likely to be selected.  This
         * causes the average number of probes for a successful search to
         * increase as the equilibrium driver runs for a long time.  To remove
         * the bias, a solution is needed to pick a key with a uniform
         * distribution when chaining is used.  It is not clear how to select a
         * key with low computational cost.
         */
    }
    printf("   Measured avg probes for unsuccessful search=%g, trials=%d\n",
           (double) unsuc_search/unsuc_trials, unsuc_trials);
    printf("    Do deletions increase avg number of probes?\n");
    performanceFormulas((double) size/TableSize);

    /* rehash and retest table */
    printf("  Rehash table\n");
    test_table = table_rehash(test_table, TableSize);
    /* number entries in table should not change */
    assert(size == table_entries(test_table));
    /* rehashing must clear all entries marked for deletion */
    assert(0 == table_deletekeys(test_table));

    /* test access times for rehashed table */

    suc_search = suc_trials = unsuc_search = unsuc_trials = 0;
    start = clock();
    /* check each position in table for key */
    if (ProbeDec == CHAIN) {
        for (i = 0; i < TableSize; i++) {
            int count = 0;
            key = table_peek(test_table, i, count);
            while (key != 0) {
                assert(MINID <= key && key <= MAXID);
                dp = table_retrieve(test_table, key);
                if (dp == NULL) {
                    printf("Failed key (%u) should be at (%d)\n", key, i);
                    exit(25);
                } else {
                    suc_search += table_stats(test_table);
                    suc_trials++;
                    assert(*(int *)dp == key);
                }
                key = table_peek(test_table, i, ++count);
            }
        }
    } else {
        for (i = 0; i < TableSize; i++) {
            key = table_peek(test_table, i, 0);
            if (key != 0) {
                assert(MINID <= key && key <= MAXID);
                dp = table_retrieve(test_table, key);
                if (dp == NULL) {
                    printf("Failed to find key (%u) after rehash but it is in location (%d)\n",
                           key, i);
                    exit(26);
                } else {
                    suc_search += table_stats(test_table);
                    suc_trials++;
                    assert(*(int *)dp == key);
                }
            }
        }
    }
    for (i = 0; i < Trials; i++) {
        /* random key with uniform distribution */
        key = (hashkey_t) (drand48() * key_range) + MINID;
        dp = table_retrieve(test_table, key);
        if (dp == NULL) {
            unsuc_search += table_stats(test_table);
            unsuc_trials++;
        } else {
            // this should be very rare
            assert(*(int *)dp == key);
        }
    }
    end = clock();
    size = table_entries(test_table);
    printf("  After rehash, time=%g\n",
           1000*((double)(end-start))/CLOCKS_PER_SEC);
    printf("   Measured avg probes for successful search=%g, trials=%d\n",
           (double) suc_search/suc_trials, suc_trials);

    printf("   Measured avg probes for unsuccessful search=%g, trials=%d\n",
           (double) unsuc_search/unsuc_trials, unsuc_trials);

    /* remove and free all items from table */
    table_destruct(test_table);

    printf("----- End of equilibrium test -----\n\n");
}
Ejemplo n.º 16
0
/* driver to test small tables.  This is a series of
 * simple tests and is not exhaustive.
 *
 * input: test_M is the table size for this test run
 */
void RehashDriver(int test_M)
{
    int i, *ip, code;
    table_t *H;

    printf("\n----- Rehash driver -----\n");
    if (ProbeDec == CHAIN) {
        printf("This design of the rehash driver does not work with separate chaining\n");
        return;
    }
    hashkey_t startkey = MINID + (test_M - MINID%test_M);
    assert(startkey%test_M == 0);
    assert(test_M > 5);  // tests designed for size at least 6

    H = table_construct(test_M, ProbeDec);
    // fill table sequentially
    for (i = 0; i < test_M-1; i++) {
        ip = (int *) malloc(sizeof(int));
        *ip = 10*i;
        assert(table_full(H) == 0);
        code = table_insert(H, startkey+i, ip);
        ip = NULL;
        assert(code == 0);
        assert(table_entries(H) == i+1);
        assert(table_stats(H) == 1);
        assert(table_peek(H,i,0) == startkey+i);
    }
    if (Verbose) {
        printf("\nfull table, last entry empty\n");
        table_debug_print(H);
    }
    // tests on empty position
    assert(table_peek(H,i,0) == 0);
    assert(NULL == table_retrieve(H, startkey+i));
    assert(table_stats(H) == 1);
    assert(table_full(H) == 1);
    assert(-1 == table_insert(H, MAXID, NULL));
    // retrieve and replace each entry
    for (i = 0; i < test_M-1; i++) {
        ip = table_retrieve(H, startkey+i);
        assert(*(int *)ip == 10*i);
        ip = NULL;
        assert(table_stats(H) == 1);
        ip = table_retrieve(H, startkey+i+test_M);
        assert(ip == NULL);
        assert(2 <= table_stats(H) && table_stats(H) <= test_M);
        if (ProbeDec == LINEAR)
            assert(table_stats(H) == i+2);
        ip = (int *) malloc(sizeof(int));
        *ip = 99*i;
        assert(1 == table_insert(H, startkey+i, ip));
        ip = NULL;
        ip = table_retrieve(H, startkey+i);
        assert(*(int *)ip == 99*i);
        ip = NULL;
    }
    assert(table_entries(H) == test_M-1);
    assert(table_full(H) == 1);
    // delete tests
    assert(table_deletekeys(H) == 0);
    ip = table_delete(H, startkey+1);
    assert(*(int *)ip == 99);
    free(ip);
    ip = NULL;
    if (Verbose) {
        printf("\nsecond entry deleted, last entry empty\n");
        table_debug_print(H);
    }
    assert(table_entries(H) == test_M-2);
    assert(table_full(H) == 0);
    assert(table_peek(H,1,0) == 0);
    assert(table_deletekeys(H) == 1);
    ip = table_retrieve(H, startkey+1);  // check key is not there
    assert(ip == NULL);
    assert(table_stats(H) >= 2);
    // attempt to delete keys not in table
    assert(NULL == table_delete(H, startkey+1));
    assert(NULL == table_delete(H, startkey+test_M-1));
    // insert key in its place
    ip = (int *) malloc(sizeof(int));
    *ip = 123;
    assert(0 == table_insert(H, startkey+1+test_M, ip));
    ip = NULL;
    assert(table_peek(H,1,0) == startkey+1+test_M);
    ip = table_retrieve(H, startkey+1+test_M);
    assert(*(int *)ip == 123);
    ip = NULL;
    assert(table_entries(H) == test_M-1);
    assert(table_full(H) == 1);
    assert(table_deletekeys(H) == 0);
    for (i = 2; i < test_M-1; i++) {     // clear out all but two keys
        ip = table_delete(H, startkey+i);
        assert(*(int *)ip == 99*i);
        free(ip);
        ip = NULL;
    }
    assert(table_entries(H) == 2);
    ip = (int *) malloc(sizeof(int));    // fill last empty
    *ip = 456;
    assert(0 == table_insert(H, startkey+test_M-1, ip));
    ip = NULL;
    assert(table_entries(H) == 3);
    // unsuccessful search when no empty keys
    assert(NULL == table_retrieve(H, startkey+test_M));

    // two keys the collide in position 0
    ip = (int *) malloc(sizeof(int));
    *ip = 77;
    assert(0 == table_insert(H, startkey+test_M, ip));
    ip = (int *) malloc(sizeof(int));
    *ip = 88;
    assert(0 == table_insert(H, startkey+10*test_M, ip));
    ip = NULL;
    assert(table_entries(H) == 5);
    ip = table_delete(H, startkey);  // delete position 0
    assert(*(int *)ip == 0);
    free(ip);
    ip = NULL;
    assert(table_entries(H) == 4);
    ip = (int *) malloc(sizeof(int));  // replace
    *ip = 87;
    assert(1 == table_insert(H, startkey+10*test_M, ip));
    ip = NULL;
    assert(table_entries(H) == 4);
    ip = (int *) malloc(sizeof(int));   // put back position 0
    *ip = 76;
    assert(0 == table_insert(H, startkey+20*test_M, ip));
    ip = NULL;
    assert(table_entries(H) == 5);
    assert(table_peek(H,0,0) == startkey+20*test_M);
    assert(table_deletekeys(H) == test_M-5);
    // verify 5 items in table
    ip = table_retrieve(H, startkey+1+test_M);
    assert(*(int *)ip == 123);
    ip = table_retrieve(H, startkey+test_M);
    assert(*(int *)ip == 77);
    ip = table_retrieve(H, startkey+10*test_M);
    assert(*(int *)ip == 87);
    ip = table_retrieve(H, startkey+20*test_M);
    assert(*(int *)ip == 76);
    ip = table_retrieve(H, startkey+test_M-1);
    assert(*(int *)ip == 456);
    ip = NULL;
    // rehash
    H = table_rehash(H, test_M);
    assert(table_entries(H) == 5);
    assert(table_deletekeys(H) == 0);
    if (Verbose) {
        printf("\ntable after rehash with 5 items\n");
        table_debug_print(H);
    }
    // verify 5 items in table
    ip = table_retrieve(H, startkey+1+test_M);
    assert(*(int *)ip == 123);
    ip = table_retrieve(H, startkey+test_M);
    assert(*(int *)ip == 77);
    ip = table_retrieve(H, startkey+10*test_M);
    assert(*(int *)ip == 87);
    ip = table_retrieve(H, startkey+20*test_M);
    assert(*(int *)ip == 76);
    ip = table_retrieve(H, startkey+test_M-1);
    assert(*(int *)ip == 456);
    ip = NULL;

    // rehash and increase table size
    // If linear double the size
    // If double, need new prime
    int new_M = 2*test_M;
    if (ProbeDec == DOUBLE)
        new_M = find_first_prime(new_M);

    H = table_rehash(H, new_M);
    assert(table_entries(H) == 5);
    assert(table_deletekeys(H) == 0);
    if (Verbose) {
        printf("\nafter increase table to %d with 5 items\n", new_M);
        table_debug_print(H);
    }
    // verify 5 keys and information not lost during rehash
    ip = table_retrieve(H, startkey+1+test_M);
    assert(*(int *)ip == 123);
    ip = table_retrieve(H, startkey+test_M);
    assert(*(int *)ip == 77);
    ip = table_retrieve(H, startkey+10*test_M);
    assert(*(int *)ip == 87);
    ip = table_retrieve(H, startkey+20*test_M);
    assert(*(int *)ip == 76);
    ip = table_retrieve(H, startkey+test_M-1);
    assert(*(int *)ip == 456);
    ip = NULL;

    // fill the new larger table
    assert(table_full(H) == 0);
    int new_items = new_M - 1 - 5;
    int base_addr = 2*startkey + 20*test_M*test_M;
    if (base_addr+new_items*test_M > MAXID) {
        printf("re-run -b driver with smaller table size\n");
        exit(1);
    }
    for (i = 0; i < new_items; i++) {
        ip = (int *) malloc(sizeof(int));
        *ip = 10*i;
        code = table_insert(H, base_addr+i*test_M, ip);
        ip = NULL;
        assert(code == 0);
        assert(table_entries(H) == i+1+5);
    }
    assert(table_full(H) == 1);
    assert(table_entries(H) == new_M-1);
    if (Verbose) {
        printf("\nafter larger table filled\n");
        table_debug_print(H);
    }
    // verify new items are found
    for (i = 0; i < new_items; i++) {
        ip = table_retrieve(H, base_addr+i*test_M);
        assert(*(int *)ip == 10*i);
        ip = NULL;
    }

    // clean up table
    table_destruct(H);
    printf("----- Passed rehash driver -----\n\n");
}