/* * pmemobj_list_remove -- removes object from a list */ int pmemobj_list_remove(PMEMobjpool *pop, size_t pe_offset, void *head, PMEMoid oid, int free) { LOG(3, "pop %p pe_offset %zu head %p oid.off 0x%016jx free %d", pop, pe_offset, head, oid.off, free); /* log notice message if used inside a transaction */ _POBJ_DEBUG_NOTICE_IN_TX(); ASSERT(OBJ_OID_IS_VALID(pop, oid)); if (pe_offset >= pop->size) { ERR("pe_offset (%lu) too big", pe_offset); return EINVAL; } if (free) { struct oob_header *pobj = OOB_HEADER_FROM_OID(pop, oid); ASSERT(pobj->data.user_type < PMEMOBJ_NUM_OID_TYPES); void *lhead = &pop->store->bytype[pobj->data.user_type].head; return list_remove_free(pop, lhead, pe_offset, head, &oid); } else return list_remove(pop, pe_offset, head, oid); }
/* * obj_free -- (internal) free an object */ static void obj_free(PMEMobjpool *pop, PMEMoid *oidp) { struct oob_header *pobj = OOB_HEADER_FROM_OID(pop, *oidp); ASSERT(pobj->data.user_type < PMEMOBJ_NUM_OID_TYPES); void *lhead = &pop->store->bytype[pobj->data.user_type].head; if (list_remove_free(pop, lhead, 0, NULL, oidp)) LOG(2, "list_remove_free failed"); }
/* * pmemobj_root_size -- returns size of the root object */ size_t pmemobj_root_size(PMEMobjpool *pop) { LOG(3, "pop %p", pop); if (pop->store->root.head.pe_first.off) { struct oob_header *ro = OOB_HEADER_FROM_OID(pop, pop->store->root.head.pe_first); return ro->size; } else return 0; }
/* * pmemobj_next - returns next object of specified type */ PMEMoid pmemobj_next(PMEMoid oid) { LOG(3, "oid.off 0x%016jx", oid.off); if (oid.off == 0) return OID_NULL; PMEMobjpool *pop = cuckoo_get(pools, oid.pool_uuid_lo); ASSERTne(pop, NULL); ASSERT(OBJ_OID_IS_VALID(pop, oid)); struct oob_header *pobj = OOB_HEADER_FROM_OID(pop, oid); uint16_t user_type = pobj->data.user_type; ASSERT(user_type < PMEMOBJ_NUM_OID_TYPES); if (pobj->oob.pe_next.off != pop->store->bytype[user_type].head.pe_first.off) return pobj->oob.pe_next; else return OID_NULL; }
/* * obj_realloc_common -- (internal) common routine for resizing * existing objects */ static int obj_realloc_common(PMEMobjpool *pop, struct object_store *store, PMEMoid *oidp, size_t size, unsigned int type_num, void (*constr_alloc)(PMEMobjpool *pop, void *ptr, void *arg), void (*constr_realloc)(PMEMobjpool *pop, void *ptr, void *arg)) { /* if OID is NULL just allocate memory */ if (OBJ_OID_IS_NULL(*oidp)) { struct carg_alloc carg; carg.size = size; /* if size is 0 - do nothing */ if (size == 0) return 0; return obj_alloc_construct(pop, oidp, size, type_num, constr_alloc, &carg); } if (size > PMEMOBJ_MAX_ALLOC_SIZE) { ERR("requested size too large"); errno = ENOMEM; return -1; } /* if size is 0 just free */ if (size == 0) { obj_free(pop, oidp); return 0; } struct carg_realloc carg; carg.ptr = OBJ_OFF_TO_PTR(pop, oidp->off); carg.new_size = size; carg.old_size = pmemobj_alloc_usable_size(*oidp); carg.user_type = type_num; carg.constructor = NULL; carg.arg = NULL; struct oob_header *pobj = OOB_HEADER_FROM_OID(pop, *oidp); uint16_t user_type_old = pobj->data.user_type; ASSERT(user_type_old < PMEMOBJ_NUM_OID_TYPES); if (type_num >= PMEMOBJ_NUM_OID_TYPES) { errno = EINVAL; ERR("!obj_realloc_construct"); LOG(2, "type_num has to be in range [0, %u]", PMEMOBJ_NUM_OID_TYPES - 1); return -1; } struct list_head *lhead_old = &store->bytype[user_type_old].head; if (type_num == user_type_old) { int ret = list_realloc(pop, lhead_old, 0, NULL, size, constr_realloc, &carg, 0, 0, oidp); if (ret) LOG(2, "list_realloc failed"); return ret; } else { struct list_head *lhead_new = &store->bytype[type_num].head; /* * Redo log updates 8 byte entries, so we have to prepare * full 8-byte value even if we want to update smaller field * (here: user_type). */ struct oob_header_data d = pobj->data; d.user_type = type_num; uint64_t data_offset = OOB_OFFSET_OF(*oidp, data); int ret = list_realloc_move(pop, lhead_old, lhead_new, 0, NULL, size, constr_realloc, &carg, data_offset, *((uint64_t *)&d), oidp); if (ret) LOG(2, "list_realloc_move failed"); return ret; } }
/* * obj_realloc_common -- (internal) common routine for resizing * existing objects */ static int obj_realloc_common(PMEMobjpool *pop, struct object_store *store, PMEMoid *oidp, size_t size, type_num_t type_num, int zero_init) { /* if OID is NULL just allocate memory */ if (OBJ_OID_IS_NULL(*oidp)) { /* if size is 0 - do nothing */ if (size == 0) return 0; return obj_alloc_construct(pop, oidp, size, type_num, zero_init, NULL, NULL); } if (size > PMEMOBJ_MAX_ALLOC_SIZE) { ERR("requested size too large"); errno = ENOMEM; return -1; } /* if size is 0 just free */ if (size == 0) { obj_free(pop, oidp); return 0; } struct carg_realloc carg; carg.ptr = OBJ_OFF_TO_PTR(pop, oidp->off); carg.new_size = size; carg.old_size = pmemobj_alloc_usable_size(*oidp); carg.user_type = type_num; carg.constructor = NULL; carg.arg = NULL; carg.zero_init = zero_init; struct oob_header *pobj = OOB_HEADER_FROM_OID(pop, *oidp); type_num_t user_type_old = pobj->data.user_type; /* callers should have checked this */ ASSERT(type_num < PMEMOBJ_NUM_OID_TYPES); ASSERT(user_type_old < PMEMOBJ_NUM_OID_TYPES); struct list_head *lhead_old = &store->bytype[user_type_old].head; if (type_num == user_type_old) { int ret = list_realloc(pop, lhead_old, 0, NULL, size, constructor_realloc, &carg, 0, 0, oidp); if (ret) LOG(2, "list_realloc failed"); /* oidp could be different, so we need to get the ptr again */ VALGRIND_DO_MAKE_MEM_NOACCESS(pop, &OOB_HEADER_FROM_OID(pop, *oidp)->data.padding, sizeof (OOB_HEADER_FROM_OID(pop, *oidp)->data.padding)); return ret; } else { struct list_head *lhead_new = &store->bytype[type_num].head; /* * Header padding doubles as a red zone to check for header * overwrites. Disable it temporarily so we can modify the type * number. */ VALGRIND_DO_MAKE_MEM_DEFINED(pop, &OOB_HEADER_FROM_OID(pop, *oidp)->data.padding, sizeof (OOB_HEADER_FROM_OID(pop, *oidp)->data.padding)); /* * Redo log updates 8 byte entries, so we have to prepare * full 8-byte value even if we want to update smaller field * (here: user_type). */ struct oob_header_data d = pobj->data; d.user_type = type_num; uint64_t data_offset = OOB_OFFSET_OF(*oidp, data); int ret = list_realloc_move(pop, lhead_old, lhead_new, 0, NULL, size, constructor_realloc, &carg, data_offset, *((uint64_t *)&d), oidp); if (ret) LOG(2, "list_realloc_move failed"); /* oidp could be different, so we need to get the ptr again */ VALGRIND_DO_MAKE_MEM_NOACCESS(pop, &OOB_HEADER_FROM_OID(pop, *oidp)->data.padding, sizeof (OOB_HEADER_FROM_OID(pop, *oidp)->data.padding)); return ret; } }