2007-07-13 19:37:47 +00:00
/* An in-memory Packed Memory Array dictionary.
The keys and values are arrays of bytes , but are not necessarily kept in scan order .
Only the pointers are kept .
*/
# include "key.h"
# include "memory.h"
# include "myassert.h"
# include "../include/ydb-constants.h"
# include <stdio.h>
# include <errno.h>
/* Only needed for testing. */
# include <string.h>
2007-08-06 19:43:27 +00:00
# include "list.h"
2007-08-03 17:21:20 +00:00
# include "kv-pair.h"
# include "pma-internal.h"
2007-09-05 20:09:43 +00:00
/* get KEY_VALUE_OVERHEAD */
# include "brt-internal.h"
2007-07-13 19:37:47 +00:00
int pma_n_entries ( PMA pma ) {
return pma - > n_pairs_present ;
}
int pma_index_limit ( PMA pma ) {
return pma - > N ;
}
2007-08-03 17:21:20 +00:00
2007-07-13 19:37:47 +00:00
int pmanode_valid ( PMA pma , int i ) {
assert ( 0 < = i ) ; assert ( i < pma_index_limit ( pma ) ) ;
2007-09-05 13:52:52 +00:00
return kv_pair_valid ( pma - > pairs [ i ] ) ;
2007-07-13 19:37:47 +00:00
}
2007-08-03 17:21:20 +00:00
2007-07-13 19:37:47 +00:00
bytevec pmanode_key ( PMA pma , int i ) {
2007-08-03 17:21:20 +00:00
struct kv_pair * pair ;
2007-07-13 19:37:47 +00:00
assert ( 0 < = i ) ; assert ( i < pma_index_limit ( pma ) ) ;
2007-08-03 17:21:20 +00:00
pair = pma - > pairs [ i ] ;
2007-09-04 13:51:12 +00:00
assert ( kv_pair_valid ( pair ) ) ;
2007-08-30 15:15:14 +00:00
return kv_pair_key ( pair ) ;
2007-07-13 19:37:47 +00:00
}
2007-08-03 17:21:20 +00:00
2007-07-13 19:37:47 +00:00
ITEMLEN pmanode_keylen ( PMA pma , int i ) {
2007-08-03 17:21:20 +00:00
struct kv_pair * pair ;
2007-07-13 19:37:47 +00:00
assert ( 0 < = i ) ; assert ( i < pma_index_limit ( pma ) ) ;
2007-08-03 17:21:20 +00:00
pair = pma - > pairs [ i ] ;
2007-09-04 13:51:12 +00:00
assert ( kv_pair_valid ( pair ) ) ;
2007-08-30 15:15:14 +00:00
return kv_pair_keylen ( pair ) ;
2007-07-13 19:37:47 +00:00
}
2007-08-03 17:21:20 +00:00
2007-07-13 19:37:47 +00:00
bytevec pmanode_val ( PMA pma , int i ) {
2007-08-03 17:21:20 +00:00
struct kv_pair * pair ;
2007-07-13 19:37:47 +00:00
assert ( 0 < = i ) ; assert ( i < pma_index_limit ( pma ) ) ;
2007-08-03 17:21:20 +00:00
pair = pma - > pairs [ i ] ;
2007-09-04 13:51:12 +00:00
assert ( kv_pair_valid ( pair ) ) ;
2007-08-30 15:15:14 +00:00
return kv_pair_val ( pair ) ;
2007-07-13 19:37:47 +00:00
}
2007-08-03 17:21:20 +00:00
2007-07-13 19:37:47 +00:00
ITEMLEN pmanode_vallen ( PMA pma , int i ) {
2007-08-03 17:21:20 +00:00
struct kv_pair * pair ;
2007-07-13 19:37:47 +00:00
assert ( 0 < = i ) ; assert ( i < pma_index_limit ( pma ) ) ;
2007-08-03 17:21:20 +00:00
pair = pma - > pairs [ i ] ;
2007-09-04 13:51:12 +00:00
assert ( kv_pair_valid ( pair ) ) ;
2007-08-30 15:15:14 +00:00
return kv_pair_vallen ( pair ) ;
2007-07-13 19:37:47 +00:00
}
/* Could pick the same one every time if we wanted. */
int pma_random_pick ( PMA pma , bytevec * key , ITEMLEN * keylen , bytevec * val , ITEMLEN * vallen ) {
# if 1
int i ;
2007-08-30 15:15:14 +00:00
2007-07-13 19:37:47 +00:00
/* For now a simple implementation where we simply start at the beginning and look. */
for ( i = 0 ; i < pma_index_limit ( pma ) ; i + + ) {
2007-08-30 15:15:14 +00:00
struct kv_pair * pair = pma - > pairs [ i ] ;
2007-09-04 13:51:12 +00:00
if ( kv_pair_valid ( pair ) ) {
2007-08-30 15:15:14 +00:00
* key = kv_pair_key ( pair ) ;
* keylen = kv_pair_keylen ( pair ) ;
* val = kv_pair_val ( pair ) ;
* vallen = kv_pair_vallen ( pair ) ;
2007-07-13 19:37:47 +00:00
return 0 ;
}
}
return DB_NOTFOUND ;
# else
/* Maybe we should pick a random item to remove in order to reduce the unbalancing. */
int i ;
int l = pma_index_limit ( pma ) ;
int r = random ( ) % l ;
/* For now a simple implementation where we simply start at the beginning and look. */
for ( i = 0 ; i < l ; i + + ) {
int ir = ( i + r ) % l ;
2007-08-30 15:15:14 +00:00
struct kv_pair * pair = pma - > pairs [ ir ] ;
2007-09-04 13:51:12 +00:00
if ( kv_pair_valid ( pair ) ) {
2007-08-30 15:15:14 +00:00
* key = kv_pair_key ( pair ) ;
* keylen = kv_pair_keylen ( pair ) ;
* val = kv_pair_val ( pair ) ;
* vallen = kv_pair_vallen ( pair ) ;
2007-07-13 19:37:47 +00:00
return 0 ;
}
}
return DB_NOTFOUND ;
# endif
}
static int pma_count_finds = 0 ;
static int pma_count_divides = 0 ;
static int pma_count_scans = 0 ;
2007-08-30 15:15:14 +00:00
2007-07-13 19:37:47 +00:00
void pma_show_stats ( void ) {
printf ( " %d finds, %d divides, %d scans \n " , pma_count_finds , pma_count_divides , pma_count_scans ) ;
}
// Return the smallest index such that no lower index contains a larger key.
// This will be in the range 0 (inclusive) to pma_index_limit(pma) (inclusive).
// Thus the returned index may not be a valid index into the array if it is == pma_index_limit(pma)
// For example: if the array is empty, that means we return 0.
// For example: if the array is full of small keys, that means we return pma_index_limit(pma), which is off the end of teh array.
// For example: if the array is full of large keys, then we return 0.
2007-07-23 20:10:16 +00:00
int pmainternal_find ( PMA pma , DBT * k , DB * db ) {
2007-07-13 19:37:47 +00:00
int lo = 0 , hi = pma_index_limit ( pma ) ;
/* lo and hi are the minimum and maximum values (inclusive) that we could possibly return. */
pma_count_finds + + ;
while ( lo < hi ) {
int mid ;
// Scan forward looking for a non-null value.
for ( mid = ( lo + hi ) / 2 ; mid < hi ; mid + + ) {
2007-09-04 13:51:12 +00:00
struct kv_pair * kv = pma - > pairs [ mid ] ;
if ( kv_pair_inuse ( kv ) ) {
2007-07-13 19:37:47 +00:00
// Found one.
2007-09-04 13:51:12 +00:00
kv = kv_pair_ptr ( kv ) ;
2007-07-23 20:10:16 +00:00
DBT k2 ;
2007-09-04 13:51:12 +00:00
int cmp = pma - > compare_fun ( db , k , fill_dbt ( & k2 , kv - > key , kv - > keylen ) ) ;
2007-07-13 19:37:47 +00:00
if ( cmp = = 0 ) return mid ;
else if ( cmp < 0 ) {
/* key is smaller than the midpoint, so look in the low half. */
hi = ( lo + hi ) / 2 ; /* recalculate the midpoint, since mid is no necessarily the midpoint now. */
pma_count_divides + + ;
goto next_range ;
} else {
/* key is larger than the midpoint. So look in the high half. */
lo = mid + 1 ; /* The smallest value we could want to return is lo. */
pma_count_divides + + ;
goto next_range ;
}
/* Not reached */
}
pma_count_scans + + ;
}
/* If we got here, all from mid to hi were null, so adjust hi to the midpoint. */
/* If the whole array is null, we'll end up returning index 0, which is good. */
hi = ( lo + hi ) / 2 ;
pma_count_divides + + ;
next_range : ; /* We have adjusted lo and hi, so look again. */
}
assert ( 0 < = lo ) ;
assert ( lo = = hi ) ;
assert ( hi < = pma_index_limit ( pma ) ) ;
2007-08-13 18:23:31 +00:00
#if 0
2007-07-13 19:37:47 +00:00
/* If lo points at something, the something should not be smaller than key. */
2007-08-03 17:21:20 +00:00
if ( lo > 0 & & lo < pma_index_limit ( pma ) & & pma - > pairs [ lo ] ) {
2007-07-13 19:37:47 +00:00
//printf("lo=%d\n", lo);
2007-07-23 20:10:16 +00:00
DBT k2 ;
2007-08-03 17:21:20 +00:00
assert ( 0 > = pma - > compare_fun ( db , k , fill_dbt ( & k2 , pma - > pairs [ lo ] - > key , pma - > pairs [ lo ] - > keylen ) ) ) ;
2007-07-13 19:37:47 +00:00
}
2007-08-13 18:23:31 +00:00
# endif
2007-07-13 19:37:47 +00:00
return lo ;
}
//int min (int i, int j) { if (i<j) return i; else return j; }
//int max (int i, int j) { if (i<j) return j; else return i; }
//double lg (int n) { return log((double)n)/log(2.0); }
2007-08-03 17:21:20 +00:00
int pmainternal_printpairs ( struct kv_pair * pairs [ ] , int N ) {
2007-07-13 19:37:47 +00:00
int count = 0 ;
int i ;
printf ( " { " ) ;
for ( i = 0 ; i < N ; i + + ) {
2007-08-03 17:21:20 +00:00
if ( i ! = 0 ) printf ( " " ) ;
2007-09-04 13:51:12 +00:00
if ( kv_pair_valid ( pairs [ i ] ) ) {
printf ( " %s " , ( char * ) kv_pair_key ( pairs [ i ] ) ) ;
2007-08-03 17:21:20 +00:00
count + + ;
}
else printf ( " _ " ) ;
2007-07-13 19:37:47 +00:00
}
printf ( " } " ) ;
return count ;
}
void print_pma ( PMA pma ) {
int count ;
printf ( " N=%d n_present=%d " , pma_index_limit ( pma ) , pma - > n_pairs_present ) ;
count = pmainternal_printpairs ( pma - > pairs , pma_index_limit ( pma ) ) ;
printf ( " \n " ) ;
assert ( count = = pma - > n_pairs_present ) ;
}
/* Smooth the data, and return the location of the null. */
2007-08-03 17:21:20 +00:00
int distribute_data ( struct kv_pair * destpairs [ ] , int dcount ,
2007-08-06 19:43:27 +00:00
struct kv_pair_tag sourcepairs [ ] , int scount , PMA pma ) {
2007-07-13 19:37:47 +00:00
assert ( scount < = dcount ) ;
if ( scount = = 0 ) {
return - 1 ;
}
if ( scount = = 1 ) {
2007-08-06 19:43:27 +00:00
destpairs [ 0 ] = sourcepairs [ 0 ] . pair ;
if ( pma )
sourcepairs [ 0 ] . newtag = destpairs - pma - > pairs ;
2007-08-03 17:21:20 +00:00
if ( destpairs [ 0 ] = = 0 ) return 0 ;
2007-07-13 19:37:47 +00:00
else return - 1 ;
} else {
int r1 = distribute_data ( destpairs , dcount / 2 ,
2007-08-06 19:43:27 +00:00
sourcepairs , scount / 2 , pma ) ;
2007-07-13 19:37:47 +00:00
int r2 = distribute_data ( destpairs + dcount / 2 , dcount - dcount / 2 ,
2007-08-06 19:43:27 +00:00
sourcepairs + scount / 2 , scount - scount / 2 , pma ) ;
2007-07-13 19:37:47 +00:00
assert ( r1 = = - 1 | | r2 = = - 1 ) ;
if ( r1 ! = - 1 ) return r1 ;
else if ( r2 ! = - 1 ) return r2 + dcount / 2 ;
else return - 1 ;
}
}
/* spread the non-empty pairs around. There are n of them. Create an empty slot just before the IDXth
element , and return that slot ' s index in the smoothed array . */
2007-08-06 19:43:27 +00:00
int pmainternal_smooth_region ( struct kv_pair * pairs [ ] , int n , int idx , int base , PMA pma ) {
2007-07-13 19:37:47 +00:00
int i ;
int n_present = 0 ;
for ( i = 0 ; i < n ; i + + ) {
2007-09-04 13:51:12 +00:00
if ( kv_pair_inuse ( pairs [ i ] ) ) n_present + + ;
2007-07-13 19:37:47 +00:00
}
n_present + + ; // Save one for the blank guy.
{
2007-08-07 22:39:23 +00:00
//#define USE_MALLOC_IN_SMOOTH
# ifdef USE_MALLOC_IN_SMOOTH
struct kv_pair_tag * MALLOC_N ( n_present , tmppairs ) ;
# else
struct kv_pair_tag tmppairs [ n_present ] ;
# endif
2007-07-13 19:37:47 +00:00
int n_saved = 0 ;
int r ;
2007-08-06 19:43:27 +00:00
2007-07-13 19:37:47 +00:00
for ( i = 0 ; i < n ; i + + ) {
if ( i = = idx ) {
2007-08-06 19:43:27 +00:00
tmppairs [ n_saved + + ] . pair = 0 ;
2007-07-13 19:37:47 +00:00
}
2007-09-04 13:51:12 +00:00
if ( kv_pair_inuse ( pairs [ i ] ) ) {
2007-08-06 19:43:27 +00:00
tmppairs [ n_saved ] . oldtag = base + i ;
tmppairs [ n_saved + + ] . pair = pairs [ i ] ;
2007-07-13 19:37:47 +00:00
}
2007-08-30 15:15:14 +00:00
pairs [ i ] = 0 ;
2007-07-13 19:37:47 +00:00
}
if ( idx = = n ) {
2007-08-06 19:43:27 +00:00
tmppairs [ n_saved + + ] . pair = 0 ;
2007-07-13 19:37:47 +00:00
}
//printf(" temp="); printpairs(tmppairs, n_saved);
assert ( n_saved = = n_present ) ;
/* Now the tricky part. Distribute the data. */
r = distribute_data ( pairs , n ,
2007-08-06 19:43:27 +00:00
tmppairs , n_saved , pma ) ;
2007-08-30 15:15:14 +00:00
if ( pma & & ! list_empty ( & pma - > cursors ) )
__pma_update_my_cursors ( pma , tmppairs , n_present ) ;
2007-08-07 22:39:23 +00:00
# ifdef USE_MALLOC_IN_SMOOTH
2007-07-20 18:00:14 +00:00
toku_free ( tmppairs ) ;
2007-08-07 22:39:23 +00:00
# endif
2007-07-13 19:37:47 +00:00
return r ;
}
}
int lg ( int n ) {
int result = 0 ;
int two_to_result = 1 ;
while ( two_to_result < n ) {
result + + ;
two_to_result * = 2 ;
}
return result ;
}
2007-08-30 15:15:14 +00:00
/* Calculate densitysteps and uplgN, given N. */
void pmainternal_calculate_parameters ( PMA pma ) {
2007-07-13 19:37:47 +00:00
int N = pma_index_limit ( pma ) ;
int lgN = lg ( N ) ;
int n_divisions = 0 ;
//printf("N=%d lgN=%d\n", N, lgN);
while ( N / 2 > = lgN ) {
n_divisions + + ;
N / = 2 ;
}
pma - > uplgN = N ;
//printf("uplgN = %d n_divisions=%d\n", pma->uplgN, n_divisions);
assert ( n_divisions > 0 ) ;
2007-08-30 15:15:14 +00:00
pma - > udt_step = ( PMA_UDT_HIGH - PMA_UDT_LOW ) / n_divisions ;
pma - > ldt_step = ( PMA_LDT_HIGH - PMA_LDT_LOW ) / n_divisions ;
2007-07-13 19:37:47 +00:00
}
2007-08-03 17:21:20 +00:00
int pmainternal_count_region ( struct kv_pair * pairs [ ] , int lo , int hi ) {
2007-07-13 19:37:47 +00:00
int n = 0 ;
while ( lo < hi ) {
2007-09-04 13:51:12 +00:00
if ( kv_pair_inuse ( pairs [ lo ] ) ) n + + ;
2007-07-13 19:37:47 +00:00
lo + + ;
}
return n ;
}
2007-07-24 14:34:05 +00:00
int pma_create ( PMA * pma , int ( * compare_fun ) ( DB * , const DBT * , const DBT * ) ) {
2007-07-30 18:35:40 +00:00
int error ;
2007-08-07 23:13:56 +00:00
TAGMALLOC ( PMA , result ) ;
2007-07-13 19:37:47 +00:00
if ( result = = 0 ) return - 1 ;
result - > n_pairs_present = 0 ;
2007-07-30 18:35:40 +00:00
result - > pairs = 0 ;
2007-08-06 19:43:27 +00:00
list_init ( & result - > cursors ) ;
2007-07-23 15:11:54 +00:00
result - > compare_fun = compare_fun ;
2007-08-06 19:43:27 +00:00
result - > skey = 0 ;
2007-07-23 20:10:16 +00:00
result - > sval = 0 ;
2007-08-30 15:15:14 +00:00
result - > N = PMA_MIN_ARRAY_SIZE ;
2007-08-06 19:43:27 +00:00
result - > pairs = 0 ;
2007-07-30 18:35:40 +00:00
2007-08-30 15:15:14 +00:00
error = __pma_resize_array ( result , result - > N , 0 ) ;
2007-07-30 18:35:40 +00:00
if ( error ) {
toku_free ( result ) ;
return - 1 ;
}
2007-07-13 19:37:47 +00:00
* pma = result ;
2007-08-03 17:21:20 +00:00
assert ( ( unsigned long ) result - > pairs [ result - > N ] = = 0xdeadbeefL ) ;
2007-07-13 19:37:47 +00:00
return 0 ;
}
2007-08-30 15:15:14 +00:00
/* find the smallest power of 2 >= n */
int __pma_array_size ( PMA pma __attribute__ ( ( unused ) ) , int asksize ) {
int n = PMA_MIN_ARRAY_SIZE ;
2007-07-30 18:35:40 +00:00
while ( n < asksize )
n * = 2 ;
2007-08-30 15:15:14 +00:00
return n ;
}
int __pma_resize_array ( PMA pma , int asksize , int startz ) {
int i ;
int n ;
2007-07-30 16:32:46 +00:00
2007-08-30 15:15:14 +00:00
n = __pma_array_size ( pma , asksize ) ;
// printf("pma_resize %d -> %d\n", pma->N, n);
2007-07-30 18:35:40 +00:00
pma - > N = n ;
2007-08-30 15:15:14 +00:00
if ( pma - > pairs = = 0 )
pma - > pairs = toku_malloc ( ( 1 + pma - > N ) * sizeof ( struct kv_pair * ) ) ;
else
pma - > pairs = toku_realloc ( pma - > pairs , ( 1 + pma - > N ) * sizeof ( struct kv_pair * ) ) ;
2007-07-30 18:35:40 +00:00
if ( pma - > pairs = = 0 )
return - 1 ;
2007-08-03 17:21:20 +00:00
pma - > pairs [ pma - > N ] = ( void * ) 0xdeadbeef ;
2007-07-30 16:32:46 +00:00
2007-08-30 15:15:14 +00:00
for ( i = startz ; i < pma - > N ; i + + ) {
2007-08-03 17:21:20 +00:00
pma - > pairs [ i ] = 0 ;
2007-07-30 16:32:46 +00:00
}
pmainternal_calculate_parameters ( pma ) ;
return 0 ;
}
2007-07-13 19:37:47 +00:00
int pma_cursor ( PMA pma , PMA_CURSOR * cursp ) {
PMA_CURSOR MALLOC ( curs ) ;
assert ( curs ! = 0 ) ;
2007-08-06 19:43:27 +00:00
if ( errno ! = 0 ) return errno ;
2007-07-13 19:37:47 +00:00
curs - > position = - 1 ; /* undefined */
curs - > pma = pma ;
curs - > skey = 0 ;
curs - > sval = 0 ;
2007-08-06 19:43:27 +00:00
list_push ( & pma - > cursors , & curs - > next ) ;
2007-07-13 19:37:47 +00:00
* cursp = curs ;
return 0 ;
}
2007-08-20 15:50:46 +00:00
int pma_cursor_get_pma ( PMA_CURSOR c , PMA * pmap ) {
* pmap = c - > pma ;
return 0 ;
}
2007-08-30 15:15:14 +00:00
int pma_cursor_set_position_last ( PMA_CURSOR c ) {
2007-07-13 19:37:47 +00:00
PMA pma = c - > pma ;
c - > position = pma - > N - 1 ;
2007-09-04 13:51:12 +00:00
while ( ! kv_pair_valid ( c - > pma - > pairs [ c - > position ] ) ) {
2007-07-13 19:37:47 +00:00
if ( c - > position > 0 ) c - > position - - ;
else return DB_NOTFOUND ;
}
return 0 ;
}
2007-08-06 19:43:27 +00:00
int pma_cursor_set_position_prev ( PMA_CURSOR c ) {
PMA pma = c - > pma ;
int old_position = c - > position ;
c - > position - - ;
while ( c - > position > = 0 ) {
2007-09-04 13:51:12 +00:00
if ( kv_pair_valid ( pma - > pairs [ c - > position ] ) ) {
if ( old_position > = 0 & & kv_pair_deleted ( pma - > pairs [ old_position ] ) & & __pma_count_cursor_refs ( pma , old_position ) = = 0 )
__pma_delete_finish ( pma , old_position ) ;
2007-08-06 19:43:27 +00:00
return 0 ;
2007-09-04 13:51:12 +00:00
}
2007-08-06 19:43:27 +00:00
c - > position - - ;
}
c - > position = old_position ;
return DB_NOTFOUND ;
}
2007-08-30 15:15:14 +00:00
int pma_cursor_set_position_first ( PMA_CURSOR c ) {
2007-07-13 19:37:47 +00:00
PMA pma = c - > pma ;
c - > position = 0 ;
2007-09-04 13:51:12 +00:00
while ( ! kv_pair_valid ( c - > pma - > pairs [ c - > position ] ) ) {
2007-07-13 19:37:47 +00:00
if ( c - > position + 1 < pma - > N ) c - > position + + ;
else return DB_NOTFOUND ;
}
return 0 ;
}
2007-08-30 15:15:14 +00:00
int pma_cursor_set_position_next ( PMA_CURSOR c ) {
2007-07-20 12:41:23 +00:00
PMA pma = c - > pma ;
int old_position = c - > position ;
c - > position + + ;
while ( c - > position < pma - > N ) {
2007-09-04 13:51:12 +00:00
if ( kv_pair_valid ( c - > pma - > pairs [ c - > position ] ) ) {
if ( old_position > = 0 & & kv_pair_deleted ( pma - > pairs [ old_position ] ) & & __pma_count_cursor_refs ( pma , old_position ) = = 0 )
__pma_delete_finish ( pma , old_position ) ;
return 0 ;
}
c - > position + + ;
2007-07-20 12:41:23 +00:00
}
c - > position = old_position ;
return DB_NOTFOUND ;
}
2007-07-13 19:37:47 +00:00
int pma_cget_current ( PMA_CURSOR c , DBT * key , DBT * val ) {
2007-09-04 13:51:12 +00:00
if ( c - > position = = - 1 )
return DB_NOTFOUND ;
2007-07-13 19:37:47 +00:00
PMA pma = c - > pma ;
2007-08-03 17:21:20 +00:00
struct kv_pair * pair = pma - > pairs [ c - > position ] ;
2007-09-04 13:51:12 +00:00
if ( ! kv_pair_valid ( pair ) )
return BRT_KEYEMPTY ;
2007-08-03 17:21:20 +00:00
ybt_set_value ( key , pair - > key , pair - > keylen , & c - > skey ) ;
ybt_set_value ( val , pair - > key + pair - > keylen , pair - > vallen , & c - > sval ) ;
2007-07-13 19:37:47 +00:00
return 0 ;
}
#if 0
int pma_cget_first ( PMA_CURSOR c , YBT * key , YBT * val ) {
PMA pma = c - > pma ;
c - > position = 0 ;
if ( pma - > n_pairs_present = = 0 ) return DB_NOTFOUND ;
while ( pma - > pairs [ c - > position ] . key = = 0 & & c - > position < pma - > N ) {
c - > position + + ;
}
assert ( c - > position < pma - > N & & pma - > pairs [ c - > position ] . key ! = 0 ) ;
ybt_set_value ( key , pma - > pairs [ c - > position ] . key , pma - > pairs [ c - > position ] . keylen , & c - > skey ) ;
ybt_set_value ( val , pma - > pairs [ c - > position ] . val , pma - > pairs [ c - > position ] . vallen , & c - > sval ) ;
return 0 ;
}
# endif
int pma_cursor_free ( PMA_CURSOR * cursp ) {
PMA_CURSOR curs = * cursp ;
2007-09-04 13:51:12 +00:00
PMA pma = curs - > pma ;
2007-08-06 19:43:27 +00:00
list_remove ( & curs - > next ) ;
2007-09-04 13:51:12 +00:00
if ( curs - > position > = 0 & & kv_pair_deleted ( pma - > pairs [ curs - > position ] ) & &
__pma_count_cursor_refs ( pma , curs - > position ) = = 0 ) {
__pma_delete_finish ( pma , curs - > position ) ;
}
2007-07-20 18:00:14 +00:00
if ( curs - > skey ) toku_free ( curs - > skey ) ;
if ( curs - > sval ) toku_free ( curs - > sval ) ;
toku_free ( curs ) ;
2007-07-13 19:37:47 +00:00
* cursp = 0 ;
return 0 ;
}
/* Make some space for a key to go at idx (the thing currently at idx should end up at to the right.) */
/* Return the new index. (Making space may involve moving things around, including the hole at index.) */
int pmainternal_make_space_at ( PMA pma , int idx ) {
/* Within a range LO to HI we have a limit of how much packing we will tolerate.
* We allow the entire array to be 50 % full .
* We allow a region of size lgN to be full .
* At sizes in between , we interpolate .
*/
int size = pma - > uplgN ;
int lo = idx ;
int hi = idx ;
2007-08-30 15:15:14 +00:00
double udt = PMA_UDT_HIGH ;
2007-07-13 19:37:47 +00:00
while ( 1 ) {
/* set hi-lo equal size, make sure it is a supserset of (hi,lo). */
lo = idx - size / 2 ;
hi = idx + size / 2 ;
//printf("lo=%d hi=%d\n", lo, hi);
if ( lo < 0 ) { hi - = lo ; lo = 0 ; }
else if ( hi > pma_index_limit ( pma ) ) { lo - = ( hi - pma_index_limit ( pma ) ) ; hi = pma_index_limit ( pma ) ; }
else { ; /* nothing */ }
//printf("lo=%d hi=%d\n", lo, hi);
assert ( 0 < = lo ) ; assert ( lo < hi ) ; assert ( hi < = pma_index_limit ( pma ) ) ; assert ( hi - lo = = size ) ; // separate into separate assertions so that gcov doesn't see branches not taken.
2007-08-30 15:15:14 +00:00
assert ( udt > 0.499 ) ; assert ( udt < = 1 ) ;
if ( udt < 0.5001 ) { assert ( lo = = 0 ) ; assert ( hi = = pma_index_limit ( pma ) ) ; }
2007-07-13 19:37:47 +00:00
{
int count = ( 1 + /* Don't forget space for the new guy. */
pmainternal_count_region ( pma - > pairs , lo , hi ) ) ;
2007-08-30 15:15:14 +00:00
double density = ( double ) count / ( double ) ( hi - lo ) ;
if ( density < = udt )
break ;
2007-07-13 19:37:47 +00:00
if ( lo = = 0 & & hi = = pma_index_limit ( pma ) ) {
/* The array needs to be doubled in size. */
2007-08-30 15:15:14 +00:00
#if 0
2007-07-13 19:37:47 +00:00
int i ;
2007-08-30 15:15:14 +00:00
# endif
2007-07-13 19:37:47 +00:00
assert ( size = = pma_index_limit ( pma ) ) ;
size * = 2 ;
2007-08-30 15:15:14 +00:00
#if 0
2007-08-03 17:21:20 +00:00
pma - > pairs = toku_realloc ( pma - > pairs , ( 1 + size ) * sizeof ( struct kv_pair * ) ) ;
for ( i = hi ; i < size ; i + + ) pma - > pairs [ i ] = 0 ;
pma - > pairs [ size ] = ( void * ) 0xdeadbeefL ;
2007-07-13 19:37:47 +00:00
pma - > N = size ;
pmainternal_calculate_parameters ( pma ) ;
2007-08-30 15:15:14 +00:00
# else
// printf("pma_make_space_realloc %d to %d hi %d\n", pma->N, size, hi);
__pma_resize_array ( pma , size , hi ) ;
# endif
2007-07-13 19:37:47 +00:00
hi = size ;
//printf("doubled N\n");
break ;
}
}
2007-08-30 15:15:14 +00:00
udt - = pma - > udt_step ;
2007-07-13 19:37:47 +00:00
size * = 2 ;
}
//printf("%s:%d Smoothing from %d to %d to density %f\n", __FILE__, __LINE__, lo, hi, density);
{
2007-08-06 19:43:27 +00:00
int new_index = pmainternal_smooth_region ( pma - > pairs + lo , hi - lo , idx - lo , lo , pma ) ;
2007-07-13 19:37:47 +00:00
return new_index + lo ;
}
}
2007-07-23 20:10:16 +00:00
enum pma_errors pma_lookup ( PMA pma , DBT * k , DBT * v , DB * db ) {
DBT k2 ;
2007-08-03 17:21:20 +00:00
struct kv_pair * pair ;
2007-07-23 20:10:16 +00:00
int l = pmainternal_find ( pma , k , db ) ;
2007-07-13 19:37:47 +00:00
assert ( 0 < = l ) ; assert ( l < = pma_index_limit ( pma ) ) ;
if ( l = = pma_index_limit ( pma ) ) return DB_NOTFOUND ;
2007-08-03 17:21:20 +00:00
pair = pma - > pairs [ l ] ;
2007-09-04 13:51:12 +00:00
if ( kv_pair_valid ( pair ) & & pma - > compare_fun ( db , k , fill_dbt ( & k2 , pair - > key , pair - > keylen ) ) = = 0 ) {
2007-08-03 17:21:20 +00:00
return ybt_set_value ( v , pair - > key + pair - > keylen , pair - > vallen , & pma - > sval ) ;
2007-07-13 19:37:47 +00:00
} else {
2007-08-03 17:21:20 +00:00
return DB_NOTFOUND ;
2007-07-13 19:37:47 +00:00
}
}
/* returns 0 if OK.
* You must have freed all the cursors , otherwise returns nonzero and does nothing . */
int pma_free ( PMA * pmap ) {
int i ;
PMA pma = * pmap ;
2007-08-16 13:10:29 +00:00
if ( ! list_empty ( & pma - > cursors ) )
return - 1 ;
if ( pma - > n_pairs_present > 0 ) {
for ( i = 0 ; i < pma - > N ; i + + ) {
2007-09-04 13:51:12 +00:00
struct kv_pair * kv = pma - > pairs [ i ] ;
if ( kv_pair_inuse ( kv ) ) {
kv_pair_free ( kv_pair_ptr ( kv ) ) ;
2007-08-16 13:10:29 +00:00
pma - > pairs [ i ] = 0 ;
pma - > n_pairs_present - - ;
}
2007-08-03 17:21:20 +00:00
}
2007-07-13 19:37:47 +00:00
}
2007-08-16 13:10:29 +00:00
assert ( pma - > n_pairs_present = = 0 ) ;
2007-07-20 18:00:14 +00:00
toku_free ( pma - > pairs ) ;
2007-07-23 20:10:16 +00:00
if ( pma - > skey ) toku_free ( pma - > skey ) ;
if ( pma - > sval ) toku_free ( pma - > sval ) ;
2007-07-31 21:59:33 +00:00
toku_free ( pma ) ;
2007-07-13 19:37:47 +00:00
* pmap = 0 ;
return 0 ;
}
/* Copies keylen and datalen */
2007-07-23 20:10:16 +00:00
int pma_insert ( PMA pma , DBT * k , DBT * v , DB * db ) {
int idx = pmainternal_find ( pma , k , db ) ;
2007-08-03 17:21:20 +00:00
if ( idx < pma_index_limit ( pma ) & & pma - > pairs [ idx ] ) {
DBT k2 ;
2007-09-04 13:51:12 +00:00
struct kv_pair * kv = kv_pair_ptr ( pma - > pairs [ idx ] ) ;
if ( 0 = = pma - > compare_fun ( db , k , fill_dbt ( & k2 , kv - > key , kv - > keylen ) ) ) {
if ( kv_pair_deleted ( pma - > pairs [ idx ] ) ) {
pma - > pairs [ idx ] = kv_pair_realloc_same_key ( kv , v - > data , v - > size ) ;
return BRT_OK ;
} else
return BRT_ALREADY_THERE ; /* It is already here. Return an error. */
2007-08-03 17:21:20 +00:00
}
2007-07-13 19:37:47 +00:00
}
2007-09-04 13:51:12 +00:00
if ( kv_pair_inuse ( pma - > pairs [ idx ] ) ) {
2007-08-03 17:21:20 +00:00
idx = pmainternal_make_space_at ( pma , idx ) ; /* returns the new idx. */
2007-07-13 19:37:47 +00:00
}
2007-09-04 13:51:12 +00:00
assert ( ! kv_pair_inuse ( pma - > pairs [ idx ] ) ) ;
2007-08-03 17:21:20 +00:00
pma - > pairs [ idx ] = kv_pair_malloc ( k - > data , k - > size , v - > data , v - > size ) ;
assert ( pma - > pairs [ idx ] ) ;
2007-07-13 19:37:47 +00:00
pma - > n_pairs_present + + ;
return BRT_OK ;
}
2007-07-23 20:10:16 +00:00
int pma_delete ( PMA pma , DBT * k , DB * db ) {
2007-08-30 15:15:14 +00:00
int l ;
l = pmainternal_find ( pma , k , db ) ;
2007-09-04 13:51:12 +00:00
struct kv_pair * kv = pma - > pairs [ l ] ;
2007-09-06 17:29:45 +00:00
if ( ! kv_pair_valid ( kv ) ) {
if ( 0 ) printf ( " %s:%d l=%d r=%d \n " , __FILE__ , __LINE__ , l , DB_NOTFOUND ) ;
2007-07-13 19:37:47 +00:00
return DB_NOTFOUND ;
}
2007-09-04 13:51:12 +00:00
pma - > pairs [ l ] = kv_pair_set_deleted ( kv ) ;
if ( __pma_count_cursor_refs ( pma , l ) = = 0 )
__pma_delete_finish ( pma , l ) ;
2007-07-13 19:37:47 +00:00
return BRT_OK ;
}
2007-09-04 13:51:12 +00:00
void __pma_delete_finish ( PMA pma , int here ) {
struct kv_pair * kv = pma - > pairs [ here ] ;
if ( ! kv_pair_inuse ( kv ) )
return ;
kv_pair_free ( kv_pair_ptr ( kv ) ) ;
pma - > pairs [ here ] = 0 ;
pma - > n_pairs_present - - ;
__pma_delete_at ( pma , here ) ;
}
2007-08-30 15:15:14 +00:00
void __pma_delete_at ( PMA pma , int here ) {
int size ;
int count ;
struct kv_pair_tag * newpairs ;
int lgN ;
double ldt ;
lgN = pma - > uplgN ;
size = lgN ;
ldt = PMA_LDT_HIGH ;
/* check the density of regions from lg(N) size to the entire array */
for ( ; ; ) {
int lo , hi ;
double density ;
/* select a region centered on here */
lo = here - size / 2 ;
hi = here + size / 2 ;
if ( lo < 0 ) {
hi - = lo ;
lo = 0 ;
if ( hi > pma - > N )
hi = pma - > N ;
} else if ( hi > pma - > N ) {
lo - = hi - pma - > N ;
hi = pma - > N ;
if ( lo < 0 )
lo = 0 ;
}
assert ( lo < = hi ) ;
/* compute the density of the region */
count = pmainternal_count_region ( pma - > pairs , lo , hi ) ;
density = ( double ) count / ( ( double ) ( hi - lo ) ) ;
/* rebalance if the density exceeds the lower threadshold */
if ( 0 ) printf ( " check size %d h %d density %d/%d %f %d-%d ldt %f \n " , size ,
lgN , count , hi - lo , density , lo , hi , ldt ) ;
if ( density > = ldt ) {
if ( size = = lgN )
return ;
if ( 0 ) printf ( " delete_at_rebalance %d over %d %d \n " , count , lo , hi ) ;
newpairs = __pma_extract_pairs ( pma , count , lo , hi ) ;
distribute_data ( pma - > pairs + lo , hi - lo , newpairs , count , pma ) ;
__pma_update_my_cursors ( pma , newpairs , count ) ;
toku_free ( newpairs ) ;
return ;
}
ldt - = pma - > ldt_step ;
size * = 2 ;
if ( 0 = = lo & & pma - > N = = hi )
break ;
}
/* shrink */
size = __pma_array_size ( pma , count + count / 4 ) ;
if ( size = = pma - > N )
return ;
if ( 0 ) printf ( " shrink %d from %d to %d \n " , count , pma - > N , size ) ;
newpairs = __pma_extract_pairs ( pma , count , 0 , pma - > N ) ;
assert ( newpairs ) ;
__pma_resize_array ( pma , size , 0 ) ;
distribute_data ( pma - > pairs , pma - > N , newpairs , count , pma ) ;
/* update the cursors */
__pma_update_my_cursors ( pma , newpairs , count ) ;
toku_free ( newpairs ) ;
}
2007-08-13 18:01:09 +00:00
int pma_insert_or_replace ( PMA pma , DBT * k , DBT * v , DB * db ,
int * replaced_v_size /* If it is a replacement, set to the size of the old value, otherwise set to -1. */
) {
2007-08-13 18:19:57 +00:00
//printf("%s:%d v->size=%d\n", __FILE__, __LINE__, v->size);
2007-08-13 18:01:09 +00:00
int idx = pmainternal_find ( pma , k , db ) ;
2007-09-04 13:51:12 +00:00
struct kv_pair * kv ;
if ( idx < pma_index_limit ( pma ) & & ( kv = pma - > pairs [ idx ] ) ) {
2007-08-13 18:01:09 +00:00
DBT k2 ;
2007-09-04 13:51:12 +00:00
kv = kv_pair_ptr ( kv ) ;
if ( 0 = = pma - > compare_fun ( db , k , fill_dbt ( & k2 , kv - > key , kv - > keylen ) ) ) {
if ( ! kv_pair_deleted ( pma - > pairs [ idx ] ) )
* replaced_v_size = kv - > vallen ;
pma - > pairs [ idx ] = kv_pair_realloc_same_key ( kv , v - > data , v - > size ) ;
return BRT_OK ;
2007-08-13 18:01:09 +00:00
}
}
2007-09-04 13:51:12 +00:00
if ( kv_pair_inuse ( pma - > pairs [ idx ] ) ) {
2007-08-13 18:01:09 +00:00
idx = pmainternal_make_space_at ( pma , idx ) ; /* returns the new idx. */
}
2007-09-04 13:51:12 +00:00
assert ( ! kv_pair_inuse ( pma - > pairs [ idx ] ) ) ;
2007-08-13 18:19:57 +00:00
//printf("%s:%d v->size=%d\n", __FILE__, __LINE__, v->size);
2007-08-13 18:01:09 +00:00
pma - > pairs [ idx ] = kv_pair_malloc ( k - > data , k - > size , v - > data , v - > size ) ;
assert ( pma - > pairs [ idx ] ) ;
pma - > n_pairs_present + + ;
* replaced_v_size = - 1 ;
return BRT_OK ;
}
2007-07-13 19:37:47 +00:00
void pma_iterate ( PMA pma , void ( * f ) ( bytevec , ITEMLEN , bytevec , ITEMLEN , void * ) , void * v ) {
int i ;
for ( i = 0 ; i < pma_index_limit ( pma ) ; i + + ) {
2007-08-03 17:21:20 +00:00
struct kv_pair * pair = pma - > pairs [ i ] ;
if ( pair ) {
f ( pair - > key , pair - > keylen ,
pair - > key + pair - > keylen , pair - > vallen , v ) ;
}
2007-07-13 19:37:47 +00:00
}
}
2007-07-30 16:32:46 +00:00
2007-09-04 13:51:12 +00:00
int __pma_count_cursor_refs ( PMA pma , int here ) {
int refs = 0 ;
struct list * list ;
struct pma_cursor * cursor ;
list = list_head ( & pma - > cursors ) ;
while ( list ! = & pma - > cursors ) {
cursor = list_struct ( list , struct pma_cursor , next ) ;
if ( cursor - > position = = here )
refs + = 1 ;
list = list - > next ;
}
return refs ;
}
2007-08-30 15:15:14 +00:00
void __pma_update_cursors_position ( PMA pma , struct list * cursor_set , int oldposition , int newposition ) {
2007-08-06 19:43:27 +00:00
struct list * list , * nextlist ;
struct pma_cursor * cursor ;
list = list_head ( cursor_set ) ;
while ( list ! = cursor_set ) {
nextlist = list - > next ; /* may be removed later */
cursor = list_struct ( list , struct pma_cursor , next ) ;
if ( cursor - > position = = oldposition ) {
2007-08-30 15:15:14 +00:00
if ( 0 ) printf ( " cursor %p %d -> %d \n " , cursor , oldposition , newposition ) ;
2007-08-06 19:43:27 +00:00
cursor - > position = newposition ;
cursor - > pma = pma ;
list_remove ( list ) ;
list_push ( & pma - > cursors , list ) ;
}
list = nextlist ;
}
}
2007-08-30 15:15:14 +00:00
void __pma_update_cursors ( PMA pma , struct list * cursor_set , struct kv_pair_tag * tpairs , int n ) {
2007-08-06 19:43:27 +00:00
/* short cut */
if ( list_empty ( cursor_set ) )
return ;
/* update all cursors to their new positions */
2007-08-30 15:15:14 +00:00
int i ;
2007-08-06 19:43:27 +00:00
for ( i = 0 ; i < n ; i + + ) {
2007-08-30 15:15:14 +00:00
if ( tpairs [ i ] . pair & & tpairs [ i ] . oldtag > = 0 )
__pma_update_cursors_position ( pma , cursor_set , tpairs [ i ] . oldtag , tpairs [ i ] . newtag ) ;
2007-08-06 19:43:27 +00:00
}
}
2007-08-30 15:15:14 +00:00
void __pma_update_my_cursors ( PMA pma , struct kv_pair_tag * tpairs , int n ) {
if ( list_empty ( & pma - > cursors ) )
return ;
struct list cursors ;
list_move ( & cursors , & pma - > cursors ) ;
__pma_update_cursors ( pma , & cursors , tpairs , n ) ;
while ( ! list_empty ( & cursors ) ) {
struct list * list = list_head ( & cursors ) ;
list_remove ( list ) ;
list_push ( & pma - > cursors , list ) ;
}
}
struct kv_pair_tag * __pma_extract_pairs ( PMA pma , int npairs , int lo , int hi ) {
2007-08-06 19:43:27 +00:00
struct kv_pair_tag * pairs ;
2007-07-30 16:32:46 +00:00
int i ;
int lastpair ;
2007-08-06 19:43:27 +00:00
pairs = toku_malloc ( npairs * sizeof ( struct kv_pair_tag ) ) ;
2007-08-03 17:21:20 +00:00
if ( pairs = = 0 )
return 0 ;
2007-07-30 16:32:46 +00:00
lastpair = 0 ;
2007-08-03 17:21:20 +00:00
for ( i = lo ; i < hi ; i + + ) {
2007-08-30 15:15:14 +00:00
assert ( 0 < = i & & i < pma - > N ) ;
2007-08-03 17:21:20 +00:00
if ( pma - > pairs [ i ] ! = 0 ) {
2007-08-30 15:15:14 +00:00
assert ( pma - > pairs [ i ] ! = ( void * ) 0xdeadbeef ) ;
2007-08-06 19:43:27 +00:00
pairs [ lastpair ] . pair = pma - > pairs [ i ] ;
pairs [ lastpair ] . oldtag = i ;
2007-08-03 17:21:20 +00:00
pma - > pairs [ i ] = 0 ;
2007-07-30 16:32:46 +00:00
lastpair + = 1 ;
}
}
assert ( lastpair = = npairs ) ;
return pairs ;
}
2007-08-09 18:54:58 +00:00
int pma_split ( PMA origpma , unsigned int * origpma_size ,
2007-08-30 15:15:14 +00:00
PMA leftpma , unsigned int * leftpma_size ,
PMA rightpma , unsigned int * rightpma_size ) {
2007-07-30 16:32:46 +00:00
int error ;
int npairs ;
2007-08-06 19:43:27 +00:00
struct kv_pair_tag * pairs ;
2007-07-30 16:32:46 +00:00
int sumlen ;
int runlen ;
int i ;
2007-08-09 18:54:58 +00:00
int n ;
2007-07-30 16:32:46 +00:00
int spliti ;
2007-08-06 19:43:27 +00:00
struct list cursors ;
2007-07-30 16:32:46 +00:00
/* extract the pairs */
2007-08-09 18:54:58 +00:00
npairs = pma_n_entries ( origpma ) ;
if ( npairs = = 0 )
return 0 ;
assert ( pma_n_entries ( leftpma ) = = 0 ) ;
assert ( pma_n_entries ( rightpma ) = = 0 ) ;
/* TODO move pairs to the stack */
2007-08-30 15:15:14 +00:00
pairs = __pma_extract_pairs ( origpma , npairs , 0 , origpma - > N ) ;
2007-08-03 17:21:20 +00:00
assert ( pairs ) ;
2007-08-09 18:54:58 +00:00
origpma - > n_pairs_present = 0 ;
2007-07-30 16:32:46 +00:00
2007-08-09 18:54:58 +00:00
/* debug check the kv length sum */
2007-07-30 16:32:46 +00:00
sumlen = 0 ;
for ( i = 0 ; i < npairs ; i + + )
2007-08-09 18:54:58 +00:00
sumlen + = kv_pair_keylen ( pairs [ i ] . pair ) + kv_pair_vallen ( pairs [ i ] . pair ) + KEY_VALUE_OVERHEAD ;
if ( origpma_size )
assert ( * ( int * ) origpma_size = = sumlen ) ;
2007-07-30 16:32:46 +00:00
runlen = 0 ;
2007-08-09 18:54:58 +00:00
for ( i = 0 ; i < npairs ; ) {
runlen + = kv_pair_keylen ( pairs [ i ] . pair ) + kv_pair_vallen ( pairs [ i ] . pair ) + KEY_VALUE_OVERHEAD ;
i + + ;
if ( 2 * runlen > = sumlen )
2007-07-30 16:32:46 +00:00
break ;
}
spliti = i ;
2007-08-09 18:54:58 +00:00
if ( leftpma_size )
* leftpma_size = runlen ;
if ( rightpma_size )
* rightpma_size = sumlen - runlen ;
2007-07-30 16:32:46 +00:00
2007-08-09 18:54:58 +00:00
/* set the cursor set to be all of the cursors from the original pma */
2007-08-06 19:43:27 +00:00
list_init ( & cursors ) ;
2007-08-09 18:54:58 +00:00
if ( ! list_empty ( & origpma - > cursors ) )
list_move ( & cursors , & origpma - > cursors ) ;
2007-08-06 19:43:27 +00:00
2007-08-09 18:54:58 +00:00
/* put the first half of pairs into the left pma */
n = spliti ;
2007-08-30 15:15:14 +00:00
error = __pma_resize_array ( leftpma , n + n / 4 , 0 ) ;
2007-07-30 18:35:40 +00:00
assert ( error = = 0 ) ;
2007-08-09 18:54:58 +00:00
distribute_data ( leftpma - > pairs , pma_index_limit ( leftpma ) , & pairs [ 0 ] , n , leftpma ) ;
2007-08-30 15:15:14 +00:00
__pma_update_cursors ( leftpma , & cursors , & pairs [ 0 ] , spliti ) ;
2007-08-09 18:54:58 +00:00
leftpma - > n_pairs_present = spliti ;
2007-07-30 16:32:46 +00:00
2007-08-09 18:54:58 +00:00
/* put the second half of pairs into the right pma */
n = npairs - spliti ;
2007-08-30 15:15:14 +00:00
error = __pma_resize_array ( rightpma , n + n / 4 , 0 ) ;
2007-07-30 18:35:40 +00:00
assert ( error = = 0 ) ;
2007-08-09 18:54:58 +00:00
distribute_data ( rightpma - > pairs , pma_index_limit ( rightpma ) , & pairs [ spliti ] , n , rightpma ) ;
2007-08-30 15:15:14 +00:00
__pma_update_cursors ( rightpma , & cursors , & pairs [ spliti ] , n ) ;
2007-08-09 18:54:58 +00:00
rightpma - > n_pairs_present = n ;
2007-07-30 16:32:46 +00:00
toku_free ( pairs ) ;
2007-08-09 18:54:58 +00:00
/* bind the remaining cursors to the left pma*/
2007-08-06 19:43:27 +00:00
while ( ! list_empty ( & cursors ) ) {
struct list * list = list_head ( & cursors ) ;
list_remove ( list ) ;
2007-08-09 18:54:58 +00:00
list_push ( & leftpma - > cursors , list ) ;
2007-08-06 19:43:27 +00:00
}
2007-07-30 16:32:46 +00:00
return 0 ;
}
2007-08-03 17:21:20 +00:00
2007-08-09 18:54:58 +00:00
int pma_get_last ( PMA pma , DBT * key , DBT * val ) {
int position ;
struct kv_pair * pair ;
void * v ; int vlen ;
2007-08-06 19:43:27 +00:00
2007-08-09 18:54:58 +00:00
position = pma - > N - 1 ;
while ( ( pair = pma - > pairs [ position ] ) = = 0 ) {
if ( position > 0 )
position - - ;
else
return DB_NOTFOUND ;
}
if ( key ) {
v = kv_pair_key ( pair ) ;
vlen = kv_pair_keylen ( pair ) ;
fill_dbt ( key , memdup ( v , vlen ) , vlen ) ;
}
if ( val ) {
v = kv_pair_val ( pair ) ;
vlen = kv_pair_vallen ( pair ) ;
fill_dbt ( val , memdup ( v , vlen ) , vlen ) ;
}
2007-08-06 19:43:27 +00:00
return 0 ;
}
void __pma_bulk_cleanup ( struct kv_pair_tag * pairs , int n ) {
int i ;
for ( i = 0 ; i < n ; i + + )
if ( pairs [ i ] . pair )
kv_pair_free ( pairs [ i ] . pair ) ;
}
int pma_bulk_insert ( PMA pma , DBT * keys , DBT * vals , int n_newpairs ) {
struct kv_pair_tag * newpairs ;
int i ;
int error ;
2007-08-09 18:54:58 +00:00
if ( n_newpairs = = 0 )
return 0 ;
if ( ! list_empty ( & pma - > cursors ) )
return - 1 ;
if ( pma_n_entries ( pma ) > 0 )
return - 2 ;
/* TODO put newpairs on the stack */
2007-08-06 19:43:27 +00:00
newpairs = toku_malloc ( n_newpairs * sizeof ( struct kv_pair_tag ) ) ;
if ( newpairs = = 0 ) {
2007-08-09 18:54:58 +00:00
error = - 3 ; return error ;
2007-08-06 19:43:27 +00:00
}
for ( i = 0 ; i < n_newpairs ; i + + ) {
newpairs [ i ] . pair = kv_pair_malloc ( keys [ i ] . data , keys [ i ] . size ,
vals [ i ] . data , vals [ i ] . size ) ;
if ( newpairs [ i ] . pair = = 0 ) {
__pma_bulk_cleanup ( newpairs , i ) ;
toku_free ( newpairs ) ;
2007-08-09 18:54:58 +00:00
error = - 4 ; return error ;
2007-08-06 19:43:27 +00:00
}
}
2007-08-30 15:15:14 +00:00
error = __pma_resize_array ( pma , n_newpairs + n_newpairs / 4 , 0 ) ;
2007-08-09 18:54:58 +00:00
if ( error ) {
2007-08-06 19:43:27 +00:00
__pma_bulk_cleanup ( newpairs , n_newpairs ) ;
2007-08-09 18:54:58 +00:00
toku_free ( newpairs ) ;
error = - 5 ; return error ;
}
distribute_data ( pma - > pairs , pma_index_limit ( pma ) , newpairs , n_newpairs , pma ) ;
pma - > n_pairs_present = n_newpairs ;
2007-08-06 19:43:27 +00:00
toku_free ( newpairs ) ;
2007-08-09 18:54:58 +00:00
return 0 ;
2007-08-06 19:43:27 +00:00
}