/* * obj_alloc_construct -- (internal) allocates a new object with constructor */ static int obj_alloc_construct(PMEMobjpool *pop, PMEMoid *oidp, size_t size, unsigned int type_num, void (*constructor)(PMEMobjpool *pop, void *ptr, void *arg), void *arg) { if (type_num >= PMEMOBJ_NUM_OID_TYPES) { errno = EINVAL; ERR("!obj_alloc_construct"); LOG(2, "type_num has to be in range [0, %i]", PMEMOBJ_NUM_OID_TYPES - 1); return -1; } if (size > PMEMOBJ_MAX_ALLOC_SIZE) { ERR("requested size too large"); errno = ENOMEM; return -1; } struct list_head *lhead = &pop->store->bytype[type_num].head; struct carg_bytype carg; carg.user_type = type_num; carg.constructor = constructor; carg.arg = arg; return list_insert_new(pop, lhead, 0, NULL, OID_NULL, 0, size, constructor_alloc_bytype, &carg, oidp); }
/* * obj_alloc_construct -- (internal) allocates a new object with constructor */ static int obj_alloc_construct(PMEMobjpool *pop, PMEMoid *oidp, size_t size, type_num_t type_num, int zero_init, void (*constructor)(PMEMobjpool *pop, void *ptr, void *arg), void *arg) { /* callers should have checked this */ ASSERT(type_num < PMEMOBJ_NUM_OID_TYPES); if (size > PMEMOBJ_MAX_ALLOC_SIZE) { ERR("requested size too large"); errno = ENOMEM; return -1; } struct list_head *lhead = &pop->store->bytype[type_num].head; struct carg_bytype carg; carg.user_type = type_num; carg.zero_init = zero_init; carg.constructor = constructor; carg.arg = arg; return list_insert_new(pop, lhead, 0, NULL, OID_NULL, 0, size, constructor_alloc_bytype, &carg, oidp); }
/* * pmemobj_list_insert_new -- adds new object to a list */ PMEMoid pmemobj_list_insert_new(PMEMobjpool *pop, size_t pe_offset, void *head, PMEMoid dest, int before, size_t size, unsigned int type_num, void (*constructor)(PMEMobjpool *pop, void *ptr, void *arg), void *arg) { LOG(3, "pop %p pe_offset %zu head %p dest.off 0x%016jx before %d" " size %zu type_num %u", pop, pe_offset, head, dest.off, before, size, type_num); /* log notice message if used inside a transaction */ _POBJ_DEBUG_NOTICE_IN_TX(); ASSERT(OBJ_OID_IS_VALID(pop, dest)); if (type_num >= PMEMOBJ_NUM_OID_TYPES) { errno = EINVAL; ERR("!pmemobj_list_insert_new"); LOG(2, "type_num has to be in range [0, %i]", PMEMOBJ_NUM_OID_TYPES - 1); return OID_NULL; } if (size > PMEMOBJ_MAX_ALLOC_SIZE) { ERR("requested size too large"); errno = ENOMEM; return OID_NULL; } if (pe_offset >= pop->size) { ERR("pe_offset (%lu) too big", pe_offset); errno = EINVAL; return OID_NULL; } struct list_head *lhead = &pop->store->bytype[type_num].head; struct carg_bytype carg; carg.user_type = (type_num_t)type_num; carg.constructor = constructor; carg.arg = arg; carg.zero_init = 0; PMEMoid retoid = OID_NULL; list_insert_new(pop, lhead, pe_offset, head, dest, before, size, constructor_alloc_bytype, &carg, &retoid); return retoid; }
/* * obj_alloc_root -- (internal) allocate root object */ static int obj_alloc_root(PMEMobjpool *pop, struct object_store *store, size_t size, void (*constructor)(PMEMobjpool *pop, void *ptr, void *arg), void *arg) { LOG(3, "pop %p store %p size %zu", pop, store, size); struct list_head *lhead = &store->root.head; struct carg_root carg; carg.size = size; carg.constructor = constructor; carg.arg = arg; return list_insert_new(pop, lhead, 0, NULL, OID_NULL, 0, size, constructor_alloc_root, &carg, NULL); }
/* * list_insert_new -- allocate and insert element to oob and user lists * * pop - pmemobj pool handle * pe_offset - offset to list entry on user list relative to user data * user_head - user list head, must be locked if not NULL * dest - destination on user list * before - insert before/after destination on user list * size - size of allocation, will be increased by OBJ_OOB_SIZE * constructor - object's constructor * arg - argument for object's constructor * oidp - pointer to target object ID */ static int list_insert_new(PMEMobjpool *pop, size_t pe_offset, struct list_head *user_head, PMEMoid dest, int before, size_t size, int (*constructor)(void *ctx, void *ptr, size_t usable_size, void *arg), void *arg, PMEMoid *oidp) { LOG(3, NULL); ASSERT(user_head != NULL); int ret; struct lane_section *lane_section; #ifdef DEBUG int r = pmemobj_mutex_assert_locked(pop, &user_head->lock); ASSERTeq(r, 0); #endif lane_hold(pop, &lane_section, LANE_SECTION_LIST); ASSERTne(lane_section, NULL); ASSERTne(lane_section->layout, NULL); struct lane_list_layout *section = (struct lane_list_layout *)lane_section->layout; struct redo_log *redo = section->redo; size_t redo_index = 0; uint64_t sec_off_off = OBJ_PTR_TO_OFF(pop, §ion->obj_offset); if (constructor) { if ((ret = pmalloc_construct(pop, §ion->obj_offset, size, constructor, arg, 0, 0, 0))) { ERR("!pmalloc_construct"); goto err_pmalloc; } } else { ret = pmalloc(pop, §ion->obj_offset, size, 0, 0); if (ret) { ERR("!pmalloc"); goto err_pmalloc; } } uint64_t obj_doffset = section->obj_offset; ASSERT((ssize_t)pe_offset >= 0); dest = list_get_dest(pop, user_head, dest, (ssize_t)pe_offset, before); struct list_entry *entry_ptr = (struct list_entry *)OBJ_OFF_TO_PTR(pop, obj_doffset + pe_offset); struct list_entry *dest_entry_ptr = (struct list_entry *)OBJ_OFF_TO_PTR(pop, dest.off + pe_offset); struct list_args_insert args = { .dest = dest, .dest_entry_ptr = dest_entry_ptr, .head = user_head, .before = before, }; struct list_args_common args_common = { .obj_doffset = obj_doffset, .entry_ptr = entry_ptr, .pe_offset = (ssize_t)pe_offset, }; uint64_t next_offset; uint64_t prev_offset; /* insert element to user list */ redo_index = list_insert_user(pop, redo, redo_index, &args, &args_common, &next_offset, &prev_offset); /* don't need to use redo log for filling new element */ list_fill_entry_persist(pop, entry_ptr, next_offset, prev_offset); if (oidp != NULL) { if (OBJ_PTR_IS_VALID(pop, oidp)) { redo_index = list_set_oid_redo_log(pop, redo, redo_index, oidp, obj_doffset, 0); } else { oidp->off = obj_doffset; oidp->pool_uuid_lo = pop->uuid_lo; } } /* clear the obj_offset in lane section */ redo_log_store_last(pop->redo, redo, redo_index, sec_off_off, 0); redo_log_process(pop->redo, redo, REDO_NUM_ENTRIES); ret = 0; err_pmalloc: lane_release(pop); ASSERT(ret == 0 || ret == -1); return ret; } /* * list_insert_new_user -- allocate and insert element to oob and user lists * * pop - pmemobj pool handle * oob_head - oob list head * pe_offset - offset to list entry on user list relative to user data * user_head - user list head * dest - destination on user list * before - insert before/after destination on user list * size - size of allocation, will be increased by OBJ_OOB_SIZE * constructor - object's constructor * arg - argument for object's constructor * oidp - pointer to target object ID */ int list_insert_new_user(PMEMobjpool *pop, size_t pe_offset, struct list_head *user_head, PMEMoid dest, int before, size_t size, int (*constructor)(void *ctx, void *ptr, size_t usable_size, void *arg), void *arg, PMEMoid *oidp) { int ret; if ((ret = pmemobj_mutex_lock(pop, &user_head->lock))) { errno = ret; LOG(2, "pmemobj_mutex_lock failed"); return -1; } ret = list_insert_new(pop, pe_offset, user_head, dest, before, size, constructor, arg, oidp); pmemobj_mutex_unlock_nofail(pop, &user_head->lock); ASSERT(ret == 0 || ret == -1); return ret; }
/* * list_insert_new -- allocate and insert element to oob and user lists * * pop - pmemobj pool handle * pe_offset - offset to list entry on user list relative to user data * user_head - user list head, must be locked if not NULL * dest - destination on user list * before - insert before/after destination on user list * size - size of allocation, will be increased by OBJ_OOB_SIZE * constructor - object's constructor * arg - argument for object's constructor * oidp - pointer to target object ID */ static int list_insert_new(PMEMobjpool *pop, size_t pe_offset, struct list_head *user_head, PMEMoid dest, int before, size_t size, uint64_t type_num, int (*constructor)(void *ctx, void *ptr, size_t usable_size, void *arg), void *arg, PMEMoid *oidp) { LOG(3, NULL); ASSERT(user_head != NULL); int ret; #ifdef DEBUG int r = pmemobj_mutex_assert_locked(pop, &user_head->lock); ASSERTeq(r, 0); #endif struct lane *lane; lane_hold(pop, &lane); struct pobj_action reserved; if (palloc_reserve(&pop->heap, size, constructor, arg, type_num, 0, 0, &reserved) != 0) { ERR("!palloc_reserve"); ret = -1; goto err_pmalloc; } uint64_t obj_doffset = reserved.heap.offset; struct operation_context *ctx = lane->external; operation_start(ctx); ASSERT((ssize_t)pe_offset >= 0); dest = list_get_dest(pop, user_head, dest, (ssize_t)pe_offset, before); struct list_entry *entry_ptr = (struct list_entry *)OBJ_OFF_TO_PTR(pop, obj_doffset + pe_offset); struct list_entry *dest_entry_ptr = (struct list_entry *)OBJ_OFF_TO_PTR(pop, dest.off + pe_offset); struct list_args_insert args = { .dest = dest, .dest_entry_ptr = dest_entry_ptr, .head = user_head, .before = before, }; struct list_args_common args_common = { .obj_doffset = obj_doffset, .entry_ptr = entry_ptr, .pe_offset = (ssize_t)pe_offset, }; uint64_t next_offset; uint64_t prev_offset; /* insert element to user list */ list_insert_user(pop, ctx, &args, &args_common, &next_offset, &prev_offset); /* don't need to use redo log for filling new element */ list_fill_entry_persist(pop, entry_ptr, next_offset, prev_offset); if (oidp != NULL) { if (OBJ_PTR_IS_VALID(pop, oidp)) { list_set_oid_redo_log(pop, ctx, oidp, obj_doffset, 0); } else { oidp->off = obj_doffset; oidp->pool_uuid_lo = pop->uuid_lo; } } palloc_publish(&pop->heap, &reserved, 1, ctx); ret = 0; err_pmalloc: lane_release(pop); ASSERT(ret == 0 || ret == -1); return ret; } /* * list_insert_new_user -- allocate and insert element to oob and user lists * * pop - pmemobj pool handle * oob_head - oob list head * pe_offset - offset to list entry on user list relative to user data * user_head - user list head * dest - destination on user list * before - insert before/after destination on user list * size - size of allocation, will be increased by OBJ_OOB_SIZE * constructor - object's constructor * arg - argument for object's constructor * oidp - pointer to target object ID */ int list_insert_new_user(PMEMobjpool *pop, size_t pe_offset, struct list_head *user_head, PMEMoid dest, int before, size_t size, uint64_t type_num, int (*constructor)(void *ctx, void *ptr, size_t usable_size, void *arg), void *arg, PMEMoid *oidp) { int ret; if ((ret = pmemobj_mutex_lock(pop, &user_head->lock))) { errno = ret; LOG(2, "pmemobj_mutex_lock failed"); return -1; } ret = list_insert_new(pop, pe_offset, user_head, dest, before, size, type_num, constructor, arg, oidp); pmemobj_mutex_unlock_nofail(pop, &user_head->lock); ASSERT(ret == 0 || ret == -1); return ret; }