2359
2573
Uint newval_sz;
2360
2574
Uint oldval_sz;
2362
2579
if (is_both_immed(newval,oldval)) {
2363
2580
handle->dbterm->tpl[position] = newval;
2582
if (handle->dbterm->debug_clone) {
2583
handle->dbterm->debug_clone[position] = newval;
2366
else if (!handle->mustResize && is_boxed(newval)) {
2367
newp = boxed_val(newval);
2368
switch (*newp & _TAG_HEADER_MASK) {
2369
case _TAG_HEADER_POS_BIG:
2370
case _TAG_HEADER_NEG_BIG:
2371
case _TAG_HEADER_FLOAT:
2372
case _TAG_HEADER_HEAP_BIN:
2373
newval_sz = header_arity(*newp) + 1;
2374
if (is_boxed(oldval)) {
2375
oldp = boxed_val(oldval);
2376
switch (*oldp & _TAG_HEADER_MASK) {
2588
if (!handle->mustResize) {
2589
if (handle->tb->common.compress) {
2590
handle->dbterm = db_alloc_tmp_uncompressed(&handle->tb->common,
2592
handle->mustResize = 1;
2593
oldval = handle->dbterm->tpl[position];
2600
ASSERT(!handle->abs_vec);
2601
old_base = handle->dbterm->tpl;
2603
if (is_boxed(newval)) {
2604
newp = boxed_val(newval);
2605
switch (*newp & _TAG_HEADER_MASK) {
2377
2606
case _TAG_HEADER_POS_BIG:
2378
2607
case _TAG_HEADER_NEG_BIG:
2379
2608
case _TAG_HEADER_FLOAT:
2380
2609
case _TAG_HEADER_HEAP_BIN:
2381
oldval_sz = header_arity(*oldp) + 1;
2382
if (oldval_sz == newval_sz) {
2383
/* "self contained" terms of same size, do memcpy */
2384
sys_memcpy(oldp, newp, newval_sz*sizeof(Eterm));
2610
newval_sz = header_arity(*newp) + 1;
2611
if (is_boxed(oldval)) {
2612
oldp = boxed_val_rel(oldval,old_base);
2613
switch (*oldp & _TAG_HEADER_MASK) {
2614
case _TAG_HEADER_POS_BIG:
2615
case _TAG_HEADER_NEG_BIG:
2616
case _TAG_HEADER_FLOAT:
2617
case _TAG_HEADER_HEAP_BIN:
2618
oldval_sz = header_arity(*oldp) + 1;
2619
if (oldval_sz == newval_sz) {
2620
/* "self contained" terms of same size, do memcpy */
2621
sys_memcpy(oldp, newp, newval_sz*sizeof(Eterm));
2634
old_base = (handle->tb->common.compress
2635
|| (handle->abs_vec && handle->abs_vec[position])) ?
2636
NULL : handle->dbterm->tpl;
2393
2639
/* Not possible for simple memcpy or dbterm is already non-contiguous, */
2394
2640
/* need to realloc... */
2396
2642
newval_sz = is_immed(newval) ? 0 : size_object(newval);
2399
oldval_sz = is_immed(oldval) ? 0 : size_object(oldval);
2645
oldval_sz = is_immed(oldval) ? 0 : size_object_rel(oldval,old_base);
2402
2648
handle->new_size = handle->new_size - oldval_sz + newval_sz;
2404
/* write new value in old dbterm, finalize will make a flat copy */
2650
/* write new value in old dbterm, finalize will make a flat copy */
2405
2651
handle->dbterm->tpl[position] = newval;
2406
2652
handle->mustResize = 1;
2655
if (old_base && newval_sz > 0) {
2656
ASSERT(!handle->tb->common.compress);
2657
if (!handle->abs_vec) {
2658
int i = header_arity(handle->dbterm->tpl[0]);
2659
handle->abs_vec = erts_alloc(ERTS_ALC_T_TMP, (i+1)*sizeof(char));
2660
sys_memset(handle->abs_vec, 0, i+1);
2661
/* abs_vec[0] not used */
2663
handle->abs_vec[position] = 1;
2668
static ERTS_INLINE byte* db_realloc_term(DbTableCommon* tb, void* old,
2669
Uint old_sz, Uint new_sz, Uint offset)
2672
if (erts_ets_realloc_always_moves) {
2673
ret = erts_db_alloc(ERTS_ALC_T_DB_TERM, (DbTable*)tb, new_sz);
2674
sys_memcpy(ret, old, offset);
2675
erts_db_free(ERTS_ALC_T_DB_TERM, (DbTable*)tb, old, old_sz);
2677
ret = erts_db_realloc(ERTS_ALC_T_DB_TERM, (DbTable*)tb,
2678
old, old_sz, new_sz);
2683
/* Allocated size of a compressed dbterm
2685
static ERTS_INLINE Uint db_alloced_size_comp(DbTerm* obj)
2687
return obj->tpl[arityval(*obj->tpl) + 1];
2690
void db_free_term(DbTable *tb, void* basep, Uint offset)
2692
DbTerm* db = (DbTerm*) ((byte*)basep + offset);
2694
if (tb->common.compress) {
2695
db_cleanup_offheap_comp(db);
2696
size = db_alloced_size_comp(db);
2700
tmp_oh.first = db->first_oh;
2701
erts_cleanup_offheap(&tmp_oh);
2702
size = offset + offsetof(DbTerm,tpl) + db->size*sizeof(Eterm);
2704
erts_db_free(ERTS_ALC_T_DB_TERM, tb, basep, size);
2707
static ERTS_INLINE Uint align_up(Uint value, Uint pow2)
2709
ASSERT((pow2 & (pow2-1)) == 0);
2710
return (value + (pow2-1)) & ~(pow2-1);
2713
/* Compressed size of an uncompressed term
2715
static Uint db_size_dbterm_comp(DbTableCommon* tb, Eterm obj)
2717
Eterm* tpl = tuple_val(obj);
2719
Uint size = sizeof(DbTerm)
2720
+ arityval(*tpl) * sizeof(Eterm)
2721
+ sizeof(Uint); /* "alloc_size" */
2723
for (i = arityval(*tpl); i>0; i--) {
2724
if (i != tb->keypos && is_not_immed(tpl[i])) {
2725
size += erts_encode_ext_size_ets(tpl[i]);
2728
size += size_object(tpl[tb->keypos]) * sizeof(Eterm);
2729
return align_up(size, sizeof(Uint));
2732
/* Conversion between top tuple element and pointer to compressed data
2734
static ERTS_INLINE Eterm ext2elem(Eterm* tpl, byte* ext)
2736
return (((Uint)(ext - (byte*)tpl)) << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER;
2738
static ERTS_INLINE byte* elem2ext(Eterm* tpl, Uint ix)
2740
ASSERT(is_header(tpl[ix]));
2741
return (byte*)tpl + (tpl[ix] >> _TAG_PRIMARY_SIZE);
2744
static void* copy_to_comp(DbTableCommon* tb, Eterm obj, DbTerm* dest,
2747
ErlOffHeap tmp_offheap;
2748
Eterm* src = tuple_val(obj);
2749
Eterm* tpl = dest->tpl;
2750
Eterm key = src[tb->keypos];
2751
int arity = arityval(src[0]);
2759
top.ep = tpl+ 1 + arity + 1;
2761
tpl[arity + 1] = alloc_size;
2763
tmp_offheap.first = NULL;
2764
tpl[tb->keypos] = copy_struct_rel(key, size_object(key), &top.ep, &tmp_offheap, NULL, tpl);
2765
dest->first_oh = tmp_offheap.first;
2766
for (i=1; i<=arity; i++) {
2767
if (i != tb->keypos) {
2768
if (is_immed(src[i])) {
2772
tpl[i] = ext2elem(tpl, top.cp);
2773
top.cp = erts_encode_ext_ets(src[i], top.cp, &dest->first_oh);
2780
Eterm* dbg_top = erts_alloc(ERTS_ALC_T_DB_TERM, dest->size * sizeof(Eterm));
2781
dest->debug_clone = dbg_top;
2782
tmp_offheap.first = dest->first_oh;
2783
copy_struct_rel(obj, dest->size, &dbg_top, &tmp_offheap, NULL, dbg_top);
2784
dest->first_oh = tmp_offheap.first;
2785
ASSERT(dbg_top == dest->debug_clone + dest->size);
2411
2792
** Copy the object into a possibly new DbTerm,
2412
2793
** offset is the offset of the DbTerm from the start
2413
** of the sysAllocaed structure, The possibly realloced and copied
2794
** of the allocated structure, The possibly realloced and copied
2414
2795
** structure is returned. Make sure (((char *) old) - offset) is a
2415
2796
** pointer to a ERTS_ALC_T_DB_TERM allocated data area.
2417
void* db_get_term(DbTableCommon *tb, DbTerm* old, Uint offset, Eterm obj)
2798
void* db_store_term(DbTableCommon *tb, DbTerm* old, Uint offset, Eterm obj)
2419
2803
int size = size_object(obj);
2420
void *structp = ((char*) old) - offset;
2804
ErlOffHeap tmp_offheap;
2425
2806
if (old != 0) {
2426
erts_cleanup_offheap(&old->off_heap);
2807
basep = ((byte*) old) - offset;
2808
tmp_offheap.first = old->first_oh;
2809
erts_cleanup_offheap(&tmp_offheap);
2810
old->first_oh = tmp_offheap.first;
2427
2811
if (size == old->size) {
2430
2815
Uint new_sz = offset + sizeof(DbTerm) + sizeof(Eterm)*(size-1);
2431
2816
Uint old_sz = offset + sizeof(DbTerm) + sizeof(Eterm)*(old->size-1);
2433
if (erts_ets_realloc_always_moves) {
2434
void *nstructp = erts_db_alloc(ERTS_ALC_T_DB_TERM,
2437
memcpy(nstructp,structp,offset);
2438
erts_db_free(ERTS_ALC_T_DB_TERM,
2444
structp = erts_db_realloc(ERTS_ALC_T_DB_TERM,
2450
p = (DbTerm*) ((void *)(((char *) structp) + offset));
2454
structp = erts_db_alloc(ERTS_ALC_T_DB_TERM,
2458
+ sizeof(Eterm)*(size-1)));
2459
p = (DbTerm*) ((void *)(((char *) structp) + offset));
2462
p->off_heap.mso = NULL;
2463
p->off_heap.externals = NULL;
2464
#ifndef HYBRID /* FIND ME! */
2465
p->off_heap.funs = NULL;
2467
p->off_heap.overhead = 0;
2469
top = DBTERM_BUF(p);
2470
copy = copy_struct(obj, size, &top, &p->off_heap);
2471
DBTERM_SET_TPL(p,tuple_val(copy));
2477
void db_free_term_data(DbTerm* p)
2479
erts_cleanup_offheap(&p->off_heap);
2818
basep = db_realloc_term(tb, basep, old_sz, new_sz, offset);
2819
newp = (DbTerm*) (basep + offset);
2823
basep = erts_db_alloc(ERTS_ALC_T_DB_TERM, (DbTable *)tb,
2824
(offset + sizeof(DbTerm) + sizeof(Eterm)*(size-1)));
2825
newp = (DbTerm*) (basep + offset);
2829
tmp_offheap.first = NULL;
2830
copy_struct_rel(obj, size, &top, &tmp_offheap, NULL, top);
2831
newp->first_oh = tmp_offheap.first;
2833
newp->debug_clone = NULL;
2839
void* db_store_term_comp(DbTableCommon *tb, DbTerm* old, Uint offset, Eterm obj)
2841
Uint new_sz = offset + db_size_dbterm_comp(tb, obj);
2846
ASSERT(tb->compress);
2848
Uint old_sz = db_alloced_size_comp(old);
2849
db_cleanup_offheap_comp(old);
2851
basep = ((byte*) old) - offset;
2852
if (new_sz == old_sz) {
2856
basep = db_realloc_term(tb, basep, old_sz, new_sz, offset);
2857
newp = (DbTerm*) (basep + offset);
2861
basep = erts_db_alloc(ERTS_ALC_T_DB_TERM, (DbTable*)tb, new_sz);
2862
newp = (DbTerm*) (basep + offset);
2865
newp->size = size_object(obj);
2866
top = copy_to_comp(tb, obj, newp, new_sz);
2867
ASSERT(top <= basep + new_sz);
2869
/* ToDo: Maybe realloc if ((basep+new_sz) - top) > WASTED_SPACE_LIMIT */
2875
void db_finalize_resize(DbUpdateHandle* handle, Uint offset)
2877
DbTable* tbl = handle->tb;
2879
Uint alloc_sz = offset +
2880
(tbl->common.compress ?
2881
db_size_dbterm_comp(&tbl->common, make_tuple(handle->dbterm->tpl)) :
2882
sizeof(DbTerm)+sizeof(Eterm)*(handle->new_size-1));
2883
byte* newp = erts_db_alloc(ERTS_ALC_T_DB_TERM, tbl, alloc_sz);
2884
byte* oldp = *(handle->bp);
2886
sys_memcpy(newp, oldp, offset); /* copy only hash/tree header */
2887
*(handle->bp) = newp;
2888
newDbTerm = (DbTerm*) (newp + offset);
2889
newDbTerm->size = handle->new_size;
2891
newDbTerm->debug_clone = NULL;
2894
/* make a flat copy */
2896
if (tbl->common.compress) {
2897
copy_to_comp(&tbl->common, make_tuple(handle->dbterm->tpl),
2898
newDbTerm, alloc_sz);
2899
db_free_tmp_uncompressed(handle->dbterm);
2902
ErlOffHeap tmp_offheap;
2903
Eterm* tpl = handle->dbterm->tpl;
2904
Eterm* top = newDbTerm->tpl;
2906
tmp_offheap.first = NULL;
2909
if (handle->abs_vec) {
2910
int i, arity = header_arity(handle->dbterm->tpl[0]);
2914
for (i=1; i<=arity; i++) {
2915
Eterm* src_base = handle->abs_vec[i] ? NULL : tpl;
2917
newDbTerm->tpl[i] = copy_struct_rel(tpl[i],
2918
size_object_rel(tpl[i],src_base),
2919
&top, &tmp_offheap, src_base,
2922
newDbTerm->first_oh = tmp_offheap.first;
2923
ASSERT((byte*)top <= (newp + alloc_sz));
2924
erts_free(ERTS_ALC_T_TMP, handle->abs_vec);
2927
#endif /* HALFWORD_HEAP */
2929
copy_struct_rel(make_tuple_rel(tpl,tpl), handle->new_size, &top,
2930
&tmp_offheap, tpl, top);
2931
newDbTerm->first_oh = tmp_offheap.first;
2932
ASSERT((byte*)top == (newp + alloc_sz));
2937
Eterm db_copy_from_comp(DbTableCommon* tb, DbTerm* bp, Eterm** hpp,
2938
ErlOffHeap* off_heap)
2941
int i, arity = arityval(bp->tpl[0]);
2946
hp[tb->keypos] = copy_struct_rel(bp->tpl[tb->keypos],
2947
size_object_rel(bp->tpl[tb->keypos], bp->tpl),
2948
hpp, off_heap, bp->tpl, NULL);
2949
for (i=arity; i>0; i--) {
2950
if (i != tb->keypos) {
2951
if (is_immed(bp->tpl[i])) {
2955
hp[i] = erts_decode_ext_ets(hpp, off_heap,
2956
elem2ext(bp->tpl, i));
2960
ASSERT((*hpp - hp) <= bp->size);
2962
ASSERT(eq_rel(make_tuple(hp),make_tuple(bp->debug_clone),bp->debug_clone));
2964
return make_tuple(hp);
2967
Eterm db_copy_element_from_ets(DbTableCommon* tb, Process* p,
2968
DbTerm* obj, Uint pos,
2969
Eterm** hpp, Uint extra)
2971
if (is_immed(obj->tpl[pos])) {
2972
*hpp = HAlloc(p, extra);
2973
return obj->tpl[pos];
2975
if (tb->compress && pos != tb->keypos) {
2976
byte* ext = elem2ext(obj->tpl, pos);
2977
Sint sz = erts_decode_ext_size_ets(ext, db_alloced_size_comp(obj)) + extra;
2978
Eterm* hp = HAlloc(p, sz);
2979
Eterm* endp = hp + sz;
2980
Eterm copy = erts_decode_ext_ets(&hp, &MSO(p), ext);
2983
HRelease(p, endp, hp);
2985
ASSERT(eq_rel(copy, obj->debug_clone[pos], obj->debug_clone));
2990
Uint sz = size_object_rel(obj->tpl[pos], obj->tpl);
2991
*hpp = HAlloc(p, sz + extra);
2992
return copy_struct_rel(obj->tpl[pos], sz, hpp, &MSO(p), obj->tpl, NULL);
2997
/* Our own "cleanup_offheap"
2998
* as refc-binaries may be unaligned in compressed terms
3000
void db_cleanup_offheap_comp(DbTerm* obj)
3002
union erl_off_heap_ptr u;
3005
for (u.hdr = obj->first_oh; u.hdr; u.hdr = u.hdr->next) {
3006
if ((UWord)u.voidp % sizeof(Uint) != 0) { /* unaligned ptr */
3007
sys_memcpy(&tmp, u.voidp, sizeof(tmp));
3008
/* Warning, must pass (void*)-variable to memcpy. Otherwise it will
3009
cause Bus error on Sparc due to false compile time assumptions
3010
about word aligned memory (type cast is not enough) */
3013
switch (thing_subtag(u.hdr->thing_word)) {
3014
case REFC_BINARY_SUBTAG:
3015
if (erts_refc_dectest(&u.pb->val->refc, 0) == 0) {
3016
erts_bin_free(u.pb->val);
3020
ASSERT(u.pb != &tmp);
3021
if (erts_refc_dectest(&u.fun->fe->refc, 0) == 0) {
3022
erts_erase_fun_entry(u.fun->fe);
3026
ASSERT(is_external_header(u.hdr->thing_word));
3027
ASSERT(u.pb != &tmp);
3028
erts_deref_node_entry(u.ext->node);
3033
if (obj->debug_clone != NULL) {
3034
erts_free(ERTS_ALC_T_DB_TERM, obj->debug_clone);
3035
obj->debug_clone = NULL;
3040
int db_eq_comp(DbTableCommon* tb, Eterm a, DbTerm* b)
3042
ErlOffHeap tmp_offheap;
3048
ASSERT(tb->compress);
3049
hp = allocp = erts_alloc(ERTS_ALC_T_TMP, b->size*sizeof(Eterm));
3050
tmp_offheap.first = NULL;
3051
tmp_b = db_copy_from_comp(tb, b, &hp, &tmp_offheap);
3052
is_eq = eq(a,tmp_b);
3053
erts_cleanup_offheap(&tmp_offheap);
3054
erts_free(ERTS_ALC_T_TMP, allocp);
2484
3059
** Check if object represents a "match" variable