Beispiel #1
0
/**
 *
 * nfs41_Session_Set
 *
 * This routine sets a session into the sessions's hashtable.
 *
 * @param psession [IN] pointer to the sessionid to be checked.
 *
 * @return 1 if ok, 0 otherwise.
 *
 */
int nfs41_Session_Set(char sessionid[NFS4_SESSIONID_SIZE],
                      nfs41_session_t * psession_data)
{
  hash_buffer_t buffkey;
  hash_buffer_t buffval;

  if(isFullDebug(COMPONENT_SESSIONS))
    {
      char str[NFS4_SESSIONID_SIZE *2 + 1];

      sprint_mem(str, (char *)sessionid, NFS4_SESSIONID_SIZE);
      LogFullDebug(COMPONENT_SESSIONS, "         -----  SetSSession : %s\n", str);
    }

  if((buffkey.pdata = (caddr_t) Mem_Alloc(NFS4_SESSIONID_SIZE)) == NULL)
    return 0;
  memcpy(buffkey.pdata, sessionid, NFS4_SESSIONID_SIZE);
  buffkey.len = NFS4_SESSIONID_SIZE;

  buffval.pdata = (caddr_t) psession_data;
  buffval.len = sizeof(nfs41_session_t);

  if(HashTable_Test_And_Set
     (ht_session_id, &buffkey, &buffval,
      HASHTABLE_SET_HOW_SET_NO_OVERWRITE) != HASHTABLE_SUCCESS)
    return 0;

  return 1;
}                               /* nfs41_Session_Set */
Beispiel #2
0
/**
 * nlm_client_Set
 * 
 *
 * This routine sets a NLM client into the related hashtable
 *
 * @return 1 if ok, 0 otherwise.
 *
 */
int nlm_client_Set(state_nlm_client_t * pkey,
                   state_nlm_client_t * pclient)
{
  hash_buffer_t buffkey;
  hash_buffer_t buffval;

  if(isFullDebug(COMPONENT_STATE) && isDebug(COMPONENT_HASHTABLE))
    {
      char str[HASHTABLE_DISPLAY_STRLEN];

      buffkey.pdata = (caddr_t) pkey;
      buffkey.len = sizeof(*pkey);

      display_nlm_client_key(&buffkey, str);
      LogFullDebug(COMPONENT_STATE,
                   "KEY {%s}", str);
    }

  buffkey.pdata = (caddr_t) pkey;
  buffkey.len = sizeof(*pkey);

  buffval.pdata = (caddr_t) pclient;
  buffval.len = sizeof(*pclient);

  if(HashTable_Test_And_Set
     (ht_nlm_client, &buffkey, &buffval,
      HASHTABLE_SET_HOW_SET_NO_OVERWRITE) != HASHTABLE_SUCCESS)
    return 0;

  return 1;
}                               /* nlm_client_Set */
Beispiel #3
0
/*----------------------------------------------------
 *              hash tables helpers
 *----------------------------------------------------*/
lookup_peer_t *h_insert_new_lookup(ino_t parent_inode,
                                   dev_t parent_dev,
                                   unsigned int parent_gen,
                                   char *name, fsnode_t * p_entry, int overwrite)
{
  hash_buffer_t buffkey;
  hash_buffer_t buffval;

  lookup_peer_t *p_lpeer;
  int flag;

  /* alloc new peer */
  p_lpeer = peer_alloc();
  if(!p_lpeer)
    return NULL;

  p_lpeer->parent.inum = parent_inode;
  p_lpeer->parent.dev = parent_dev;
  p_lpeer->parent.generation = parent_gen;
  strncpy(p_lpeer->name, name, FSAL_MAX_NAME_LEN);

  buffkey.pdata = (caddr_t) p_lpeer;
  buffkey.len = sizeof(*p_lpeer);

  buffval.pdata = (caddr_t) p_entry;
  buffval.len = sizeof(*p_entry);

  if(overwrite)
    flag = HASHTABLE_SET_HOW_SET_OVERWRITE;
  else
    flag = HASHTABLE_SET_HOW_SET_NO_OVERWRITE;

  if(HashTable_Test_And_Set(lookup_hash, &buffkey, &buffval, flag) != HASHTABLE_SUCCESS)
    {
      peer_free(p_lpeer);
      return NULL;
    }

  /* Add lookup to node and increase n_lookup count */
  p_entry->n_lookup++;
  p_lpeer->p_next = p_entry->parent_list;
  p_entry->parent_list = p_lpeer;

  return p_lpeer;

}                               /* h_insert_new_lookup */
Beispiel #4
0
fsnode_t *h_insert_new_node(ino_t inode, dev_t device, unsigned int gen, int overwrite)
{
  hash_buffer_t buffkey;
  hash_buffer_t buffval;

  fsnode_t *p_node;
  int flag;

  p_node = node_alloc();
  if(!p_node)
    return NULL;

  p_node->inode.inum = inode;
  p_node->inode.dev = device;

  p_node->inode.generation = gen;

  /* no children, no hardlink for the moment */
  p_node->n_lookup = 0;
  p_node->n_children = 0;
  p_node->parent_list = NULL;

  /* insert it to hash table */

  buffkey.pdata = (caddr_t) & p_node->inode;
  buffkey.len = sizeof(p_node->inode);

  buffval.pdata = (caddr_t) p_node;
  buffval.len = sizeof(*p_node);

  if(overwrite)
    flag = HASHTABLE_SET_HOW_SET_OVERWRITE;
  else
    flag = HASHTABLE_SET_HOW_SET_NO_OVERWRITE;

  if(HashTable_Test_And_Set(nodes_hash, &buffkey, &buffval, flag) != HASHTABLE_SUCCESS)
    {
      node_free(p_node);
      return NULL;
    }

  return p_node;

}                               /* h_insert_new_node */
Beispiel #5
0
/**
 * nfs4_owner_Set
 *
 *
 * This routine sets a open owner into the related hashtable
 *
 * @return 1 if ok, 0 otherwise.
 *
 */
int nfs4_owner_Set(state_nfs4_owner_name_t * pname,
                   state_owner_t           * powner)
{
  hash_buffer_t buffkey;
  hash_buffer_t buffval;
  int rc;

  buffkey.pdata = (caddr_t) pname;
  buffkey.len = sizeof(state_nfs4_owner_name_t);

  if(isFullDebug(COMPONENT_STATE) && isDebug(COMPONENT_HASHTABLE))
    {
      char str[HASHTABLE_DISPLAY_STRLEN];

      display_nfs4_owner_key(&buffkey, str);
      LogFullDebug(COMPONENT_STATE,
                   "KEY {%s}", str);
    }

  buffval.pdata = (caddr_t) powner;
  buffval.len = sizeof(state_owner_t);

  P(nfs4_owner_counter_lock);
  nfs4_owner_counter += 1;
  powner->so_owner.so_nfs4_owner.so_counter = nfs4_owner_counter;
  V(nfs4_owner_counter_lock);

  rc = HashTable_Test_And_Set
     (ht_nfs4_owner, &buffkey, &buffval,
      HASHTABLE_SET_HOW_SET_NO_OVERWRITE);
  if(rc != HASHTABLE_SUCCESS)
    {
      LogDebug(COMPONENT_STATE,
               "Failed to insert nfs4 owner into hash table rc = %d", rc);
      return 0;
    }

  return 1;
}                               /* nfs4_owner_Set */
Beispiel #6
0
int nfs_dupreq_add_not_finished(long xid,
                                struct svc_req *ptr_req,
                                SVCXPRT *xprt,
                                struct prealloc_pool *dupreq_pool,
                                nfs_res_t *res_nfs)
{
  hash_buffer_t buffkey;
  hash_buffer_t buffval;
  hash_buffer_t buffdata;
  dupreq_entry_t *pdupreq = NULL;
  int status = 0;
  dupreq_key_t *pdupkey = NULL;
  
  /* Entry to be cached */
  GetFromPool(pdupreq, dupreq_pool, dupreq_entry_t);
  if(pdupreq == NULL)
    return DUPREQ_INSERT_MALLOC_ERROR;

  if((pdupkey = (dupreq_key_t *) Mem_Alloc(sizeof(dupreq_key_t))) == NULL)
    {
      ReleaseToPool(pdupreq, dupreq_pool);
      return DUPREQ_INSERT_MALLOC_ERROR;
    }

  /* Get the socket address for the key and the request */
  if(copy_xprt_addr(&pdupkey->addr, xprt) == 0 ||
     copy_xprt_addr(&pdupreq->addr, xprt) == 0)
    {
      Mem_Free(pdupkey);
      ReleaseToPool(pdupreq, dupreq_pool);
      return DUPREQ_INSERT_MALLOC_ERROR;
    }

  pdupkey->xid = xid;
  pdupreq->xid = xid;

  /* Checksum the request */
  pdupkey->checksum = 0;
  pdupreq->checksum = 0;

  /* I have to keep an integer as key, I wil use the pointer buffkey->pdata for this,
   * this also means that buffkey->len will be 0 */
  buffkey.pdata = (caddr_t) pdupkey;
  buffkey.len = sizeof(dupreq_key_t);

  /* I build the data with the request pointer that should be in state 'IN USE' */
  pdupreq->rq_prog = ptr_req->rq_prog;
  pdupreq->rq_vers = ptr_req->rq_vers;
  pdupreq->rq_proc = ptr_req->rq_proc;
  pdupreq->timestamp = time(NULL);
  pdupreq->processing = 1;
  buffdata.pdata = (caddr_t) pdupreq;
  buffdata.len = sizeof(dupreq_entry_t);

  LogDupReq("Add Not Finished", &pdupreq->addr, pdupreq->xid, pdupreq->rq_prog);

  status = HashTable_Test_And_Set(ht_dupreq, &buffkey, &buffdata,
                                  HASHTABLE_SET_HOW_SET_NO_OVERWRITE);

  if (status == HASHTABLE_ERROR_KEY_ALREADY_EXISTS)
    {
      if(HashTable_Get(ht_dupreq, &buffkey, &buffval) == HASHTABLE_SUCCESS)
        {
          P(((dupreq_entry_t *)buffval.pdata)->dupreq_mutex);
          if ( ((dupreq_entry_t *)buffval.pdata)->processing == 1)
            {
              V(((dupreq_entry_t *)buffval.pdata)->dupreq_mutex);
              status = DUPREQ_BEING_PROCESSED;
            }
          else
            {
              *res_nfs = ((dupreq_entry_t *) buffval.pdata)->res_nfs;
              V(((dupreq_entry_t *)buffval.pdata)->dupreq_mutex);
              status = DUPREQ_ALREADY_EXISTS;
            }
        }
      else
        status = DUPREQ_NOT_FOUND;
    }
  else if (status == HASHTABLE_INSERT_MALLOC_ERROR)
      status = DUPREQ_INSERT_MALLOC_ERROR;
  else
    status = DUPREQ_SUCCESS;
  if (status != DUPREQ_SUCCESS)
    ReleaseToPool(pdupreq, dupreq_pool);
  return status;
}                               /* nfs_dupreq_add_not_finished */
Beispiel #7
0
fsal_acl_t *nfs4_acl_new_entry(fsal_acl_data_t *pacldata, fsal_acl_status_t *pstatus)
{
  fsal_acl_t *pacl = NULL;
  hash_buffer_t buffkey;
  hash_buffer_t buffvalue;
  int rc;

  /* Set the return default to NFS_V4_ACL_SUCCESS */
  *pstatus = NFS_V4_ACL_SUCCESS;

  LogDebug(COMPONENT_NFS_V4_ACL, "nfs4_acl_new_entry: acl hash table size = %u",
           HashTable_GetSize(fsal_acl_hash));

  /* Turn the input to a hash key */
  if(nfs4_acldata_2_key(&buffkey, pacldata))
    {
      *pstatus = NFS_V4_ACL_UNAPPROPRIATED_KEY;

      nfs4_release_acldata_key(&buffkey);

      nfs4_ace_free(pacldata->aces);

      return NULL;
    }

  /* Check if the entry doesn't already exists */
  if(HashTable_Get(fsal_acl_hash, &buffkey, &buffvalue) == HASHTABLE_SUCCESS)
    {
      /* Entry is already in the cache, do not add it */
      pacl = (fsal_acl_t *) buffvalue.pdata;
      *pstatus = NFS_V4_ACL_EXISTS;

      nfs4_release_acldata_key(&buffkey);

      nfs4_ace_free(pacldata->aces);

      return pacl;
    }

  /* Adding the entry in the cache */
  pacl = nfs4_acl_alloc();
  if(rw_lock_init(&(pacl->lock)) != 0)
    {
      nfs4_acl_free(pacl);
      LogCrit(COMPONENT_NFS_V4_ACL,
              "nfs4_acl_new_entry: rw_lock_init returned %d (%s)",
              errno, strerror(errno));
      *pstatus = NFS_V4_ACL_INIT_ENTRY_FAILED;

      nfs4_release_acldata_key(&buffkey);

      nfs4_ace_free(pacldata->aces);

      return NULL;
    }

  pacl->naces = pacldata->naces;
  pacl->aces = pacldata->aces;
  pacl->ref = 0;

  /* Build the value */
  buffvalue.pdata = (caddr_t) pacl;
  buffvalue.len = sizeof(fsal_acl_t);

  if((rc =
      HashTable_Test_And_Set(fsal_acl_hash, &buffkey, &buffvalue,
                             HASHTABLE_SET_HOW_SET_NO_OVERWRITE)) != HASHTABLE_SUCCESS)
    {
      /* Put the entry back in its pool */
      nfs4_acl_free(pacl);
      LogWarn(COMPONENT_NFS_V4_ACL,
              "nfs4_acl_new_entry: entry could not be added to hash, rc=%d",
              rc);

      if( rc != HASHTABLE_ERROR_KEY_ALREADY_EXISTS )
       {
         *pstatus = NFS_V4_ACL_HASH_SET_ERROR;

         nfs4_release_acldata_key(&buffkey);

         return NULL;
       }
     else
      {
        LogDebug(COMPONENT_NFS_V4_ACL,
                 "nfs4_acl_new_entry: concurrency detected during acl insertion");

        /* This situation occurs when several threads try to init the same uncached entry
         * at the same time. The first creates the entry and the others got  HASHTABLE_ERROR_KEY_ALREADY_EXISTS
         * In this case, the already created entry (by the very first thread) is returned */
        if((rc = HashTable_Get(fsal_acl_hash, &buffkey, &buffvalue)) != HASHTABLE_SUCCESS)
         {
            *pstatus = NFS_V4_ACL_HASH_SET_ERROR;

            nfs4_release_acldata_key(&buffkey);

            return NULL;
         }

        pacl = (fsal_acl_t *) buffvalue.pdata;
        *pstatus = NFS_V4_ACL_SUCCESS;

        nfs4_release_acldata_key(&buffkey);

        return pacl;
      }
    }

  return pacl;
}
Beispiel #8
0
int main(int argc, char *argv[])
{
  SetDefaultLogging("TEST");
  SetNamePgm("test_cmchash");

  hash_table_t *ht = NULL;
  hash_parameter_t hparam;
  hash_buffer_t buffval;
  hash_buffer_t buffkey;
  hash_buffer_t buffval2;
  hash_buffer_t buffkey2;
  hash_stat_t statistiques;
  int i;
  int val;
  int rc;
  int res;
  struct Temps debut, fin;
  char tmpstr[10];
  char tmpstr2[10];
  char tmpstr3[10];
  char strtab[MAXTEST][10];
  int critere_recherche = 0;
  int random_val = 0;

  hparam.index_size = PRIME;
  hparam.alphabet_length = 10;
  hparam.nb_node_prealloc = NB_PREALLOC;
  hparam.hash_func_key = simple_hash_func;
  hparam.hash_func_rbt = rbt_hash_func;
  hparam.compare_key = compare_string_buffer;
  hparam.key_to_str = display_buff;
  hparam.val_to_str = display_buff;

  BuddyInit(NULL);

  /* Init de la table */
  if((ht = HashTable_Init(hparam)) == NULL)
    {
      LogTest("Test FAILED: Bad init");
      exit(1);
    }

  MesureTemps(&debut, NULL);
  LogTest("Created the table");

  for(i = 0; i < MAXTEST; i++)
    {
      sprintf(strtab[i], "%d", i);

      buffkey.len = strlen(strtab[i]);
      buffkey.pdata = strtab[i];

      buffval.len = strlen(strtab[i]);
      buffval.pdata = strtab[i];

      rc = HashTable_Set(ht, &buffkey, &buffval);
      LogFullDebug(COMPONENT_HASHTABLE,"Added %s , %d , return = %d", strtab[i], i, rc);
    }

  MesureTemps(&fin, &debut);
  LogTest("Time to insert %d entries: %s", MAXTEST,
         ConvertiTempsChaine(fin, NULL));

  LogFullDebug(COMPONENT_HASHTABLE, "-----------------------------------------");
  HashTable_Log(COMPONENT_HASHTABLE,ht);

  LogTest("=========================================");

  /* Premier test simple: verif de la coherence des valeurs lues */
  critere_recherche = CRITERE;

  sprintf(tmpstr, "%d", critere_recherche);
  buffkey.len = strlen(tmpstr);
  buffkey.pdata = tmpstr;

  MesureTemps(&debut, NULL);
  rc = HashTable_Get(ht, &buffkey, &buffval);
  MesureTemps(&fin, &debut);

  LogTest("Recovery of %d th key ->%d", critere_recherche, rc);

  LogTest("Time to recover = %s", ConvertiTempsChaine(fin, NULL));

  if(rc != HASHTABLE_SUCCESS)
    {
      LogTest("Test FAILED: The key is not found");
      exit(1);
    }

  sprintf(tmpstr, "%d", critere_recherche);
  buffkey.len = strlen(tmpstr);
  buffkey.pdata = tmpstr;

  MesureTemps(&debut, NULL);
  rc = HashTable_Get(ht, &buffkey, &buffval);
  MesureTemps(&fin, &debut);

  LogTest("Recovery of %d th key (test 2) -> %s", critere_recherche, rc);

  LogTest("Time to recover = %s", ConvertiTempsChaine(fin, NULL));

  if(rc != HASHTABLE_SUCCESS)
    {
      LogTest("Test FAILED: The key is not found (test 2)");
      exit(1);
    }

  LogTest("----> retrieved value = len %d ; val = %s", buffval.len, buffval.pdata);
  val = atoi(buffval.pdata);

  if(val != critere_recherche)
    {
      LogTest("Test FAILED: the reading is incorrect");
      exit(1);
    }

  LogTest("Now, I try to retrieve %d entries (taken at random, almost)",
         MAXGET);
  MesureTemps(&debut, NULL);
  for(i = 0; i < MAXGET; i++)
    {
      random_val = random() % MAXTEST;
      sprintf(tmpstr, "%d", random_val);
      buffkey2.len = strlen(tmpstr);
      buffkey2.pdata = tmpstr;

      rc = HashTable_Get(ht, &buffkey2, &buffval2);
      LogFullDebug(COMPONENT_HASHTABLE,"\tPlaying key = %s  --> %s", buffkey2.pdata, buffval2.pdata);
      if(rc != HASHTABLE_SUCCESS)
        {
          LogTest("Error reading %d = %d", i, rc);
          LogTest("Test FAILED: the reading is incorrect");
          exit(1);
        }
    }
  MesureTemps(&fin, &debut);
  LogTest("Time to read %d elements = %s", MAXGET,
         ConvertiTempsChaine(fin, NULL));

  LogTest("-----------------------------------------");

  sprintf(tmpstr, "%d", critere_recherche);
  buffkey.len = strlen(tmpstr);
  buffkey.pdata = tmpstr;

  rc = HashTable_Del(ht, &buffkey, NULL, NULL);
  LogTest("Deleting the key %d --> %d", critere_recherche, rc);

  if(rc != HASHTABLE_SUCCESS)
    {
      LogTest("Test FAILED: delete incorrect");
      exit(1);
    }

  LogTest("=========================================");

  sprintf(tmpstr, "%d", critere_recherche);
  buffkey.len = strlen(tmpstr);
  buffkey.pdata = tmpstr;

  rc = HashTable_Del(ht, &buffkey, NULL, NULL);
  LogTest("Deleting the key %d (2nd try) --> %d", critere_recherche, rc);

  if(rc != HASHTABLE_ERROR_NO_SUCH_KEY)
    {
      printf("Test FAILED: delete incorrect");
      exit(1);
    }

  LogTest("=========================================");

  sprintf(tmpstr, "%d", critere_recherche);
  buffkey.len = strlen(tmpstr);
  buffkey.pdata = tmpstr;

  rc = HashTable_Get(ht, &buffkey, &buffval);
  LogTest
      ("Recovery of the %d key (erased) (must return HASH_ERROR_NO_SUCH_KEY) = %d --> %d",
       critere_recherche, HASHTABLE_ERROR_NO_SUCH_KEY, rc);

  if(rc != HASHTABLE_ERROR_NO_SUCH_KEY)
    {
      LogTest("Test FAILED: the reading is incorrect");
      exit(1);
    }
  LogTest("-----------------------------------------");

  LogTest
      ("Destruction of %d items, taken at random (well if you want ... I use srandom)",
       MAXDESTROY);
  srandom(getpid());
  random_val = random() % MAXTEST;

  MesureTemps(&debut, NULL);
  for(i = 0; i < MAXDESTROY; i++)
    {
      /* 
      it used to be that the random values were chosen with
      repeated calls to random(), but if the same key comes up twice,
      that causes a fail.  This way we start with a random value and
      just linearly delete from it
      */

      random_val = (random_val + 1) % MAXTEST;
      sprintf(tmpstr, "%d", random_val);
      LogTest("\t Delete %d", random_val);
      buffkey.len = strlen(tmpstr);
      buffkey.pdata = tmpstr;

      rc = HashTable_Del(ht, &buffkey, NULL, NULL);
      

      if(rc != HASHTABLE_SUCCESS)
        {
          LogTest("Error on delete %d = %d", i, rc);
          LogTest("Test FAILED: delete incorrect");
          exit(1);
        }
    }
  MesureTemps(&fin, &debut);
  LogTest("Time to delete %d elements = %s", MAXDESTROY,
         ConvertiTempsChaine(fin, NULL));

  LogTest("-----------------------------------------");

  LogTest("Now, I try to retrieve %d entries (if necessary destroyed)",
         MAXGET);
  MesureTemps(&debut, NULL);
  for(i = 0; i < MAXGET; i++)
    {
      random_val = random() % MAXTEST;
      sprintf(tmpstr, "%d", random_val);
      buffkey.len = strlen(tmpstr);
      buffkey.pdata = tmpstr;

      rc = HashTable_Get(ht, &buffkey, &buffval);
    }
  MesureTemps(&fin, &debut);
  LogTest("Tie to read %d elements = %s", MAXGET,
         ConvertiTempsChaine(fin, NULL));

  LogTest("-----------------------------------------");
  LogTest("Writing a duplicate key ");
  sprintf(tmpstr, "%d", CRITERE_2);
  buffkey.len = strlen(tmpstr);
  buffkey.pdata = tmpstr;
  rc = HashTable_Test_And_Set(ht, &buffkey, &buffval, HASHTABLE_SET_HOW_SET_NO_OVERWRITE);
  LogTest("The value should be HASHTABLE_ERROR_KEY_ALREADY_EXISTS  = %d --> %d",
         HASHTABLE_ERROR_KEY_ALREADY_EXISTS, rc);
  if(rc != HASHTABLE_ERROR_KEY_ALREADY_EXISTS)
    {
      LogTest("Test FAILED: duplicate key");
      exit(1);
    }
  LogTest("-----------------------------------------");

  HashTable_Log(COMPONENT_HASHTABLE,ht);
  LogFullDebug(COMPONENT_HASHTABLE,"-----------------------------------------");

  LogTest("Displaying table statistics ");
  HashTable_GetStats(ht, &statistiques);
  LogTest(" Number of entries = %d", statistiques.dynamic.nb_entries);

  LogTest("   Successful operations  : Set = %d,  Get = %d,  Del = %d,  Test = %d",
         statistiques.dynamic.ok.nb_set, statistiques.dynamic.ok.nb_get,
         statistiques.dynamic.ok.nb_del, statistiques.dynamic.ok.nb_test);

  LogTest("   Failed operations : Set = %d,  Get = %d,  Del = %d,  Test = %d",
         statistiques.dynamic.err.nb_set, statistiques.dynamic.err.nb_get,
         statistiques.dynamic.err.nb_del, statistiques.dynamic.err.nb_test);

  LogTest("   Operations 'NotFound': Set = %d,  Get = %d,  Del = %d,  Test = %d",
         statistiques.dynamic.notfound.nb_set, statistiques.dynamic.notfound.nb_get,
         statistiques.dynamic.notfound.nb_del, statistiques.dynamic.notfound.nb_test);

  LogTest
      ("  Calculated statistics: min_rbt_node = %d,  max_rbt_node = %d,  average_rbt_node = %d",
       statistiques.computed.min_rbt_num_node, statistiques.computed.max_rbt_num_node,
       statistiques.computed.average_rbt_num_node);

  /* Test sur la pertinence des valeurs de statistiques */
  if(statistiques.dynamic.ok.nb_set != MAXTEST)
    {
      LogTest("Test FAILED: Incorrect statistics: ok.nb_set ");
      exit(1);
    }

  if(statistiques.dynamic.ok.nb_get + statistiques.dynamic.notfound.nb_get !=
     2 * MAXGET + 3)
    {
      LogTest("Test FAILED: Incorrect statistics: *.nb_get ");
      exit(1);
    }

  if(statistiques.dynamic.ok.nb_del != MAXDESTROY + 1
     || statistiques.dynamic.notfound.nb_del != 1)
    {
      LogTest("Test ECHOUE : statistiques incorrectes: *.nb_del ");
      exit(1);
    }

  if(statistiques.dynamic.err.nb_test != 1)
    {
      LogTest("Test ECHOUE : statistiques incorrectes: err.nb_test ");
      exit(1);
    }

  /* Tous les tests sont ok */
  BuddyDumpMem(stdout);

  LogTest("\n-----------------------------------------");
  LogTest("Test succeeded: all tests pass successfully");

  exit(0);
}
int main(int argc, char *argv[])
{
  SetDefaultLogging("TEST");
  SetNamePgm("test_libcmc_bugdelete");
  LogTest("Initialized test program");
  
  hash_table_t *ht = NULL;
  hash_parameter_t hparam;
  hash_buffer_t buffval;
  hash_buffer_t buffkey;
  hash_buffer_t buffval2;
  hash_buffer_t buffkey2;
  hash_stat_t statistiques;
  int i;
  int rc;
  struct Temps debut, fin;
  char tmpstr[10];
  char strtab[MAXTEST][10];
  int critere_recherche = 0;
  int random_val = 0;

  hparam.index_size = PRIME;
  hparam.alphabet_length = 10;
  hparam.nb_node_prealloc = NB_PREALLOC;
  hparam.hash_func_key = simple_hash_func;
  hparam.hash_func_rbt = rbt_hash_func;
  hparam.hash_func_both = NULL ; /* BUGAZOMEU */
  hparam.compare_key = compare_string_buffer;
  hparam.key_to_str = display_buff;
  hparam.val_to_str = display_buff;

  BuddyInit(NULL);

  /* Init de la table */
  if((ht = HashTable_Init(hparam)) == NULL)
    {
      LogTest("Test FAILED: Bad init");
      exit(1);
    }

  MesureTemps(&debut, NULL);
  LogTest("Created hash table");

  for(i = 0; i < MAXTEST; i++)
    {
      sprintf(strtab[i], "%d", i);

      buffkey.len = strlen(strtab[i]);
      buffkey.pdata = strtab[i];

      buffval.len = strlen(strtab[i]);
      buffval.pdata = strtab[i];

      rc = HashTable_Set(ht, &buffkey, &buffval);
      LogFullDebug(COMPONENT_HASHTABLE,
                   "Added %s , %d , return code = %d", strtab[i], i, rc);
    }

  MesureTemps(&fin, &debut);
  LogTest("Time to insert %d entries: %s", MAXTEST,
         ConvertiTempsChaine(fin, NULL));

  LogFullDebug(COMPONENT_HASHTABLE,
               "-----------------------------------------");
  HashTable_Log(COMPONENT_HASHTABLE, ht);
  LogFullDebug(COMPONENT_HASHTABLE,
               "=========================================");

  /* Premier test simple: verif de la coherence des valeurs lues */
  critere_recherche = CRITERE;

  sprintf(tmpstr, "%d", critere_recherche);
  buffkey.len = strlen(tmpstr);
  buffkey.pdata = tmpstr;

  MesureTemps(&debut, NULL);
  rc = HashTable_Get(ht, &buffkey, &buffval);
  MesureTemps(&fin, &debut);

  LogTest("Now, I try to retrieve %d entries (taken at random, almost)",
          MAXGET);

  MesureTemps(&debut, NULL);
  for(i = 0; i < MAXGET; i++)
    {
      random_val = random() % MAXTEST;
      sprintf(tmpstr, "%d", random_val);
      buffkey2.len = strlen(tmpstr);
      buffkey2.pdata = tmpstr;

      rc = HashTable_Get(ht, &buffkey2, &buffval2);
      LogTest("\tPlaying key = %s  --> %s", buffkey2.pdata, buffval2.pdata);
      if(rc != HASHTABLE_SUCCESS)
        {
          LogTest("Error reading %d = %d", i, rc);
          LogTest("Test FAILED: the reading is incorrect");
          exit(1);
        }
    }
  MesureTemps(&fin, &debut);
  LogTest("Time to read elements %d = %s", MAXGET,
         ConvertiTempsChaine(fin, NULL));

  LogTest("-----------------------------------------");

  sprintf(tmpstr, "%d", critere_recherche);
  buffkey.len = strlen(tmpstr);
  buffkey.pdata = tmpstr;

  sprintf(tmpstr, "%d", critere_recherche);
  buffkey.len = strlen(tmpstr);
  buffkey.pdata = tmpstr;

  sprintf(tmpstr, "%d", critere_recherche);
  buffkey.len = strlen(tmpstr);
  buffkey.pdata = tmpstr;

  srandom(getpid());

  MesureTemps(&debut, NULL);
  for(i = 0; i < MAXDESTROY; i++)
    {
      random_val = bugdelete_key_array[i];
      sprintf(tmpstr, "%d", random_val);

      buffkey.len = strlen(tmpstr);
      buffkey.pdata = tmpstr;
      LogFullDebug(COMPONENT_HASHTABLE, "\t Erase %u -> %lu | %lu",
                   random_val,
                   simple_hash_func(&hparam, &buffkey),
                   rbt_hash_func(&hparam, &buffkey));

      rc = HashTable_Del(ht, &buffkey, NULL, NULL);
      if(rc != HASHTABLE_SUCCESS)
        {
          LogTest("Erreur lors de la destruction de %d = %d", random_val, rc);
          LogTest("Test FAILED: delete incorrect");
          exit(1);
        }
    }
  MesureTemps(&fin, &debut);
  LogTest("Time to delete %d elements = %s", MAXDESTROY,
          ConvertiTempsChaine(fin, NULL));

  LogTest("-----------------------------------------");

  LogTest("Now, I try to retrieve %d entries (possibly destroyed)",
          MAXGET);

  MesureTemps(&debut, NULL);
  for(i = 0; i < MAXGET; i++)
    {
      random_val = random() % MAXTEST;
      sprintf(tmpstr, "%d", random_val);
      buffkey.len = strlen(tmpstr);
      buffkey.pdata = tmpstr;

      rc = HashTable_Get(ht, &buffkey, &buffval);
    }
  MesureTemps(&fin, &debut);
  LogTest("Time to read %d elements = %s", MAXGET,
          ConvertiTempsChaine(fin, NULL));

  LogTest("-----------------------------------------");
  LogTest("Writing a duplicated key");
  sprintf(tmpstr, "%d", CRITERE_2);
  buffkey.len = strlen(tmpstr);
  buffkey.pdata = tmpstr;
  rc = HashTable_Test_And_Set(ht, &buffkey, &buffval, HASHTABLE_SET_HOW_SET_NO_OVERWRITE);
  LogTest("The value must be HASHTABLE_ERROR_KEY_ALREADY_EXISTS  = %d --> %d",
         HASHTABLE_ERROR_KEY_ALREADY_EXISTS, rc);
  if(rc != HASHTABLE_ERROR_KEY_ALREADY_EXISTS)
    {
      LogTest("Test ECHOUE : Clef redondante");
      exit(1);
    }
  LogTest("-----------------------------------------");

  HashTable_Log(COMPONENT_HASHTABLE,ht);
  LogFullDebug(COMPONENT_HASHTABLE,"-----------------------------------------");

  LogTest("Displaying table statistics");
  HashTable_GetStats(ht, &statistiques);
  LogTest(" Number of Entrees = %d", statistiques.dynamic.nb_entries);

  LogTest(" Successful operations : Set = %d,  Get = %d,  Del = %d,  Test = %d",
          statistiques.dynamic.ok.nb_set, statistiques.dynamic.ok.nb_get,
          statistiques.dynamic.ok.nb_del, statistiques.dynamic.ok.nb_test);

  LogTest("   Failed operations : Set = %d,  Get = %d,  Del = %d,  Test = %d",
          statistiques.dynamic.err.nb_set, statistiques.dynamic.err.nb_get,
          statistiques.dynamic.err.nb_del, statistiques.dynamic.err.nb_test);

  LogTest("   Operations 'NotFound': Set = %d,  Get = %d,  Del = %d,  Test = %d",
          statistiques.dynamic.notfound.nb_set, statistiques.dynamic.notfound.nb_get,
          statistiques.dynamic.notfound.nb_del, statistiques.dynamic.notfound.nb_test);

  LogTest("  Statistics computed: min_rbt_node = %d,  max_rbt_node = %d,  average_rbt_node = %d",
          statistiques.computed.min_rbt_num_node, statistiques.computed.max_rbt_num_node,
          statistiques.computed.average_rbt_num_node);

  /* Test sur la pertinence des valeurs de statistiques */
  if(statistiques.dynamic.ok.nb_set != MAXTEST)
    {
      LogTest("Test FAILED: Incorrect statistics: ok.nb_set ");
      exit(1);
    }

  if(statistiques.dynamic.ok.nb_get + statistiques.dynamic.notfound.nb_get !=
     2 * MAXGET + 1)
    {
      LogTest("Test FAILED: Incorrect statistics: *.nb_get.  Expected %d, got %d",
              2 * MAXGET + 1,
              statistiques.dynamic.ok.nb_get + statistiques.dynamic.notfound.nb_get);
      exit(1);
    }

  if(statistiques.dynamic.ok.nb_del != MAXDESTROY)
    {
      LogTest("Test FAILED: Incorrect statistics: *.nb_del. Expected %d, got %d",
              MAXDESTROY, statistiques.dynamic.ok.nb_del);
      exit(1);
    }

  if(statistiques.dynamic.notfound.nb_del != 0)
    {
      LogTest("Test FAILED: Incorrect statistics: *.nb_del. Expected %d, got %d",
              0, statistiques.dynamic.notfound.nb_del);
      exit(1);
    }



  if(statistiques.dynamic.err.nb_test != 1)
    {
      LogTest("Test FAILED: Incorrect statistics: err.nb_test ");
      exit(1);
    }

  /* Tous les tests sont ok */
  BuddyDumpMem(stdout);

  LogTest("\n-----------------------------------------");
  LogTest("Test succeeded: all tests pass successfully");

  exit(0);
}