diff --git a/doc/libpmemobj/pmemobj_ctl_get.3.md b/doc/libpmemobj/pmemobj_ctl_get.3.md index fafbd6d4c99bd32c1369ecc913c97c29ddfebd4e..82118190882226ffb15a79fb7dcbd794a311acd0 100644 --- a/doc/libpmemobj/pmemobj_ctl_get.3.md +++ b/doc/libpmemobj/pmemobj_ctl_get.3.md @@ -206,7 +206,7 @@ Reads or modifies the state of the arena. If set, the arena is used in automatic scheduling of memory operations for threads. This should be set to false if the application wants to manually manage allocator scalability through explicitly assigning arenas to threads by using heap.thread.arena_id. -The arena id cannot be 0. +The arena id cannot be 0 and at least one automatic arena must exist. heap.alloc_class.[class_id].desc | rw | - | `struct pobj_alloc_class_desc` | `struct pobj_alloc_class_desc` | - | integer, integer, integer, string diff --git a/src/libpmemobj/heap.c b/src/libpmemobj/heap.c index 355ef4a925fe2199e6cf04e23a19e206cb28771f..8b948484f29aa473122f6c8002719559652906b9 100644 --- a/src/libpmemobj/heap.c +++ b/src/libpmemobj/heap.c @@ -222,6 +222,8 @@ heap_thread_arena_assign(struct heap_rt *heap) LOG(4, "assigning %p arena to current thread", least_used); + /* at least one automatic arena must exist */ + ASSERTne(least_used, NULL); util_fetch_and_add64(&least_used->nthreads, 1); util_mutex_unlock(&heap->arenas_lock); @@ -1124,13 +1126,33 @@ heap_get_arena_auto(struct palloc_heap *heap, unsigned arena_id) /* * heap_set_arena_auto -- sets arena automatic value */ -void +int heap_set_arena_auto(struct palloc_heap *heap, unsigned arena_id, int automatic) { - struct arena *a = heap_get_arena_by_id(heap, arena_id); + unsigned nautomatic = 0; + struct arena *a; + struct heap_rt *h = heap->rt; + int ret = 0; + + util_mutex_lock(&h->arenas_lock); + VEC_FOREACH(a, &h->arenas) + if (a->automatic) + nautomatic++; + a = VEC_ARR(&heap->rt->arenas)[arena_id - 1]; + + if (!automatic && nautomatic <= 1 && a->automatic) { + ERR("at least one automatic arena must exist"); + ret = -1; + goto out; + } a->automatic = automatic; + +out: + util_mutex_unlock(&h->arenas_lock); + return ret; + } /* diff --git a/src/libpmemobj/heap.h b/src/libpmemobj/heap.h index 08609af39c2f9dd6f02f858661d2880fca5bcebe..57ea16a6a1154151e7dba8843093c0480240a277 100644 --- a/src/libpmemobj/heap.h +++ b/src/libpmemobj/heap.h @@ -122,7 +122,7 @@ heap_get_arena_buckets(struct palloc_heap *heap, unsigned arena_id); int heap_get_arena_auto(struct palloc_heap *heap, unsigned arena_id); -void heap_set_arena_auto(struct palloc_heap *heap, unsigned arena_id, +int heap_set_arena_auto(struct palloc_heap *heap, unsigned arena_id, int automatic); void heap_set_arena_thread(struct palloc_heap *heap, unsigned arena_id); diff --git a/src/libpmemobj/pmalloc.c b/src/libpmemobj/pmalloc.c index db3f6daa9a17702800d1847d940bd7f6b8e99c01..89cae449cc82ad8e11116ab2b1f85992275cccfd 100644 --- a/src/libpmemobj/pmalloc.c +++ b/src/libpmemobj/pmalloc.c @@ -666,9 +666,7 @@ CTL_WRITE_HANDLER(automatic)(void *ctx, enum ctl_query_source source, return -1; } - heap_set_arena_auto(&pop->heap, arena_id, arg_in); - - return 0; + return heap_set_arena_auto(&pop->heap, arena_id, arg_in); } /* diff --git a/src/test/obj_ctl_arenas/obj_ctl_arenas.c b/src/test/obj_ctl_arenas/obj_ctl_arenas.c index 8a6a980065c87c0a7404973de046d4a9ebf78b64..d5edbb32683f1f3449e1546b68ac2cc4b806132a 100644 --- a/src/test/obj_ctl_arenas/obj_ctl_arenas.c +++ b/src/test/obj_ctl_arenas/obj_ctl_arenas.c @@ -379,6 +379,35 @@ main(int argc, char *argv[]) ret = pmemobj_ctl_get(pop, "heap.narenas.total", &narenas_a); UT_ASSERTeq(ret, 0); UT_ASSERTeq(narenas_b + narenas_n, narenas_a); + + /* at least one automatic arena must exist */ + for (unsigned i = 1; i <= narenas_a; i++) { + ret = snprintf(arena_idx_auto, CTL_QUERY_LEN, + "heap.arena.%u.automatic", i); + if (ret < 0 || ret >= CTL_QUERY_LEN) + UT_FATAL("!snprintf arena_idx_auto"); + + automatic = 0; + if (i < narenas_a) { + ret = pmemobj_ctl_set(pop, arena_idx_auto, + &automatic); + UT_ASSERTeq(ret, 0); + } else { + /* + * last auto arena - + * cannot change the state to 0... + */ + ret = pmemobj_ctl_set(pop, arena_idx_auto, + &automatic); + UT_ASSERTeq(ret, -1); + + /* ...but can change (overwrite) to 1 */ + automatic = 1; + ret = pmemobj_ctl_set(pop, arena_idx_auto, + &automatic); + UT_ASSERTeq(ret, 0); + } + } } else if (t == 'a') { int ret; unsigned arena_id_new;