Пример #1
0
void hashtable_install( obj table, obj hash, obj key, obj value )
{
  obj vec, bucket;
  UINT_32 i;

  inserting_one( table );
  vec = gvec_read( table, HASHTABLE_DIRECTORY );
    
  for (bucket = read_dir(vec,hash);
       !EQ(bucket,FALSE_OBJ);
       bucket = gvec_read( bucket, BUCKET_OVERFLOW ))
    {
      for (i=SLOT(2); i<SLOT(2+BUCKET_CAPACITY); i+=sizeof(obj))
	{
	  if (EQ(read_bucket_hash(bucket,i),FALSE_OBJ))
	    {
	      write_bucket_hash( bucket, i, hash );
	      write_bucket_key( bucket, i, key );
	      write_bucket_value( bucket, i, value );
	      return;
	    }
	}
    }

  /* grow things... */
    
  split_bucket( table, read_dir( vec, hash ), hash, key, value );
}
Пример #2
0
// insert 'key' into 'table', if it's not in there already
// returns true if insertion succeeds, false if it was already in there
bool xtndbln_hash_table_insert(XtndblNHashTable *table, int64 key) {
	assert(table);
	int start_time = clock(); // Start timing
	
	// Calculate table address
	int hash = h1(key);
	int address = rightmostnbits(table->depth, hash);
	int i, no_keys = table->buckets[address]->nkeys;
	
	
	// Check whether the key have been inserted or not
	if (table->buckets[address]->nkeys > 0) {
		
		table->stats.time += clock() - start_time; // Add time elapsed
		// Iterate through the keys in this bucket
		for (i = 0; i < no_keys; i++) {
			
			// The key have been inserted before
			if (table->buckets[address]->keys[i] == key) {
				
				// add time elapsed to total CPU time before returning
				table->stats.time += clock() - start_time;
				
				return false;	
			}
		}
	}
	
	// If not, try to insert the key to the table
	while (table->buckets[address]->nkeys == table->bucketsize) {
		
		split_bucket(table, address);
		
		// and recalculate address because we might now need more bits
		address = rightmostnbits(table->depth, hash);
	}
	
	no_keys = table->buckets[address]->nkeys;
	
	// There is now space! Just insert the key
	table->buckets[address]->keys[no_keys] = key;
	table->buckets[address]->nkeys++;
	table->stats.nkeys++;
	
	// add time elapsed to total CPU time before returning
	table->stats.time += clock() - start_time;

	return true;
}
Пример #3
0
// insert 'key' into 'table', if it's not in there already
// returns true if insertion succeeds, false if it was already in there
bool xuckoo_hash_table_insert(XuckooHashTable *table, int64 key) {
	assert(table);
	int start_time = clock();
	
	int total_kicked_keys = 0, hash;
	int64 kick_key;
	InnerTable *innertable = table->table1;

	// Calculate table address
	int hash_1 = h1(key), hash_2 = h2(key);
	int address_1 = rightmostnbits(table->table1->depth, hash_1);
	int address_2 = rightmostnbits(table->table2->depth, hash_2);
	int address = address_1;
	
	// Check the key in table 1
	if (table->table1->buckets[address_1]->full && 
		table->table1->buckets[address_1]->key == key) {
		table->stats.time += clock() - start_time; // Add time elapsed
		return false;
	}
		
	// Check the key in table 2
	if (table->table2->buckets[address_2]->full && 
		table->table2->buckets[address_2]->key == key) {
		table->stats.time += clock() - start_time; // Add time elapsed
		return false;
	}
	
	// Check which table that has the least keys
	int insert_table = 1;
	if (table->table1->nkeys > table->table2->nkeys) {
		insert_table = 2;
	}
	
	// Try to find an empty slot and check if there is a cycle
	while (innertable->buckets[address]->full && 
		total_kicked_keys != 2*(table->table1->size)) {
		kick_key = innertable->buckets[address]->key;
		total_kicked_keys++;
		
		innertable->buckets[address]->key = key;
		key = kick_key;
		
		// If it kicked the key from the Table 1, need to insert the kicked 
		// key to the Table 2 
		if (insert_table == 1) {
			
			// Mark the next table that will be visited is table 2
			insert_table = 2;
				
			// Update the temp_table and the hash
			innertable = table->table2;
			address = rightmostnbits(innertable->depth, h2(key));
		}
		
		// If it kicked the key from the Table 2, need to insert the kicked 
		// key to the Table 1
		else if (insert_table == 2) {
			
			// Mark the next table that will be visited is table 2
			insert_table = 1;
				
			// Update the temp_table and the hash
			innertable = table->table1;
			address = rightmostnbits(innertable->depth, h1(key));
		}	
	}
	
	// The number of kicked key is equal to the 2 times the table size,
	// indicates that there is a cycling, so we need to grow the table
	if (total_kicked_keys == 2*(table->table1->size)) {
		
		// Make space on the smallest size table to have space to 
		// insert the key
		while (innertable->buckets[address]->full) {
			
			// If the first table has size smaller than or equal to the second
			// table's size, choose the first table
			if (table->table1->size <= table->table2->size) {
				innertable = table->table1;
				hash = h1(key);
				address = rightmostnbits(innertable->depth, hash);
				insert_table = 1;
			}
			
			// Otherwise, choose the second table
			else {
				innertable = table->table2;
				hash = h2(key);
				address = rightmostnbits(innertable->depth, hash);
				insert_table = 2;
			}
			
			split_bucket(innertable, address, insert_table);
			
			// and recalculate address because we might now need more bits
			address = rightmostnbits(innertable->depth, hash);
		}
	}
	
	// There is now space for the key, so we can just insert it
	innertable->buckets[address]->key = key;
	innertable->buckets[address]->full = true;
	innertable->nkeys++;
	
	table->stats.time += clock() - start_time; // Add time elapsed
	return true;
	
}
Пример #4
0
int add(struct config *c, DB *dbp, ReadingSet *rs) {
  int cur_rec, ret;
  DBC *cursorp;
  struct rec_key cur_k;
  struct rec_val cur_v;
  DB_TXN *tid = NULL;
  unsigned char buf[POINT_OFF(MAXBUCKETRECS + NBUCKETSIZES)];
  struct rec_val *v = (struct rec_val *)buf;
  struct point *rec_data = v->data;
  bool_t bucket_dirty = FALSE, bucket_valid = FALSE;
  unsigned long long dirty_start = ULLONG_MAX, dirty_end = 0;

  bzero(&cur_k, sizeof(cur_k));
  bzero(&cur_v, sizeof(cur_v));

  if ((ret = env->txn_begin(env, NULL, &tid, 0)) != 0) {
    error("txn_begin: %s\n", db_strerror(ret));
    return -1;
  }
  
  if ((ret = dbp->cursor(dbp, tid, &cursorp, 0)) != 0) {
    error("db cursor: %s\n", db_strerror(ret));
    goto abort;
  }
  if (cursorp == NULL) {
    dbp->err(dbp, ret, "cursor");
    goto abort;
  }

  for (cur_rec = 0; cur_rec < rs->n_data; cur_rec++) {
    debug("Adding reading ts: 0x%x\n", rs->data[cur_rec]->timestamp);
    if (bucket_valid &&
        v->n_valid > 0 &&
        cur_k.stream_id == rs->streamid &&
        cur_k.timestamp <= rs->data[cur_rec]->timestamp &&
        cur_k.timestamp + v->period_length > rs->data[cur_rec]->timestamp) {
      /* we're already in the right bucket; don't need to do anything */
      debug("In valid bucket.  n_valid: %i\n", v->n_valid);
    } else {
      /* need to find the right bucket */
      debug("Looking up bucket\n");
      assert(!bucket_valid || POINT_OFF(v->n_valid) < sizeof(buf));
      if (bucket_valid == TRUE && 
          (ret = put(dbp, tid, &cur_k, v, POINT_OFF(v->n_valid))) < 0) {
        warn("error writing back data: %s\n", db_strerror(ret));
        // we will loose data, aborto the transaction.
        goto abort;
      }
      bucket_valid = FALSE;

      cur_k.stream_id = rs->streamid;
      cur_k.timestamp = rs->data[cur_rec]->timestamp;

      if ((ret = get_bucket(cursorp, &cur_k, &cur_v)) <= 0) {
        /* create a new bucket */

        /* the key has been updated by get_bucket */
        v->n_valid = 0;
        v->period_length = bucket_sizes[-ret];
        v->tail_timestamp = 0;
        debug("Created new bucket anchor: %i length: %i\n", cur_k.timestamp, v->period_length);
      } else {
        debug("Found existing bucket streamid: %i anchor: %i length: %i\n", 
              cur_k.stream_id, cur_k.timestamp, v->period_length);
        if ((ret = get(cursorp, DB_SET | DB_RMW, &cur_k, v, sizeof(buf))) < 0) {
          warn("error reading bucket: %s\n", db_strerror(ret));
          goto abort;
        }
      }
      bucket_valid = TRUE;
    }

    debug("v->: tail_timestamp: %i n_valid: %i\n", v->tail_timestamp, v->n_valid);
    /* start the insert -- we're in the current bucket */
    if (v->tail_timestamp < rs->data[cur_rec]->timestamp ||
        v->n_valid == 0) {
      /* if it's an append or a new bucket we can just write the values */
      /* update the header block */
      v->tail_timestamp = rs->data[cur_rec]->timestamp;
      v->n_valid++;
      /* and the data */
      _rpc_copy_records(&v->data[v->n_valid-1], &rs->data[cur_rec], 1);
      debug("Append detected; inserting at offset: %i\n", POINT_OFF(v->n_valid-1));
    } else {
      struct rec_val *v = (struct rec_val *)buf;
      struct point new_rec;
      int i;
      /* otherwise we have to insert it somewhere. we'll just read out
         all the data and do the insert stupidly. */
      for (i = 0; i < v->n_valid; i++) {
        if (v->data[i].timestamp >= rs->data[cur_rec]->timestamp)
          break;
      }
      debug("Inserting within existing bucket index: %i (%i %i)\n", 
            i, rs->data[cur_rec]->timestamp, v->tail_timestamp);
      /* appends should have been handled without reading back the whole record */
      assert(i < v->n_valid);
      /* we have our insert position */
      if (v->data[i].timestamp == rs->data[cur_rec]->timestamp) {
        /* replace a record */
        debug("Replacing record with timestamp 0x%x\n", rs->data[cur_rec]->timestamp);
        _rpc_copy_records(&v->data[i], &rs->data[cur_rec], 1);
      } else {
        /* shift the existing records back */
        debug("Inserting new record (moving %i recs)\n", v->n_valid - i);
        memmove(&v->data[i+1], &v->data[i], (v->n_valid - i) * sizeof(struct point));
        _rpc_copy_records(&v->data[i], &rs->data[cur_rec], 1);
        v->n_valid++;
        /* and update the header */
      }
    }
    bucket_dirty = TRUE;
    assert(v->n_valid < MAXBUCKETRECS + NBUCKETSIZES);

    if (v->n_valid > MAXBUCKETRECS) {
      debug("Splitting buckets since this one is full!\n");
      /* start by writing the current bucket back */
      assert(POINT_OFF(v->n_valid) < sizeof(buf));
      if (bucket_valid == TRUE && 
          (ret = put(dbp, tid, &cur_k, v, POINT_OFF(v->n_valid))) < 0) {
        bucket_valid = FALSE;
        warn("error writing back data: %s\n", db_strerror(ret));
        goto abort;
      }

      if (split_bucket(dbp, cursorp, tid, &cur_k) < 0)
        goto abort;
      bzero(&cur_k, sizeof(cur_k));
      bzero(&cur_v, sizeof(cur_v));
    }

    /* find the time region this write dirties  */
    if (rs->data[cur_rec]->timestamp < dirty_start) {
      dirty_start = rs->data[cur_rec]->timestamp;
    }
    if (rs->data[cur_rec]->timestamp > dirty_end) {
      dirty_end = rs->data[cur_rec]->timestamp;
    }
  }

  if (bucket_valid && bucket_dirty) {
    debug("flushing bucket back to db\n");
    assert(POINT_OFF(v->n_valid) < sizeof(buf));
    if ((ret = put(dbp, tid, &cur_k, v, POINT_OFF(v->n_valid))) < 0) {
      warn("error writing back data: %s\n", db_strerror(ret));
      goto abort;
    }
  }

  cursorp->close(cursorp);

  if ((ret = tid->commit(tid, 0)) != 0) {
    fatal("transaction commit failed: %s\n", db_strerror(ret));
    // SDH : "If DB_TXN->commit() encounters an error, the transaction
    //  and all child transactions of the transaction are aborted."
    //
    // So, we can just die here.
    // do_shutdown = 1;
    return -1;
  }

  //
  if (dirty_start != ULLONG_MAX && dirty_end != 0) {
    mark_sketch_dirty(c, rs->streamid, dirty_start, dirty_end);
  }

  return 0;

 abort:
  cursorp->close(cursorp);
  warn("Aborting transaction\n");

  if ((ret = tid->abort(tid)) != 0) {
    fatal("Could not abort transaction: %s\n", db_strerror(ret));
    // do_shutdown = 1;
    // SDH : there are no documented error codes for DB_TXN->abort().
    assert(0);
  }
  return -1;
}