From c43725e1891bd8534ac4b668277cddae9762d524 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 5 Mar 2020 16:17:14 +0100 Subject: Add an session-wise uuid integer to IDs. "session-wise" here mean while editing a same .blend file. So creating or opening a new one will reset the uuid counter. This should avoid any overflow in practice. Only IDs added to Main database get an uuid, runtime-only ones are not affected. This is intended to provide undo with a way to find IDs across several 'memory realms' (undo speedup project). No behavior change is expected from this commit itself. Part of T60695. Differential Revision: https://developer.blender.org/D7007 --- source/blender/blenkernel/BKE_lib_id.h | 8 +++ source/blender/blenkernel/BKE_main_idmap.h | 20 +++++-- source/blender/blenkernel/intern/lib_id.c | 31 +++++++++++ source/blender/blenkernel/intern/main_idmap.c | 68 +++++++++++++++++------ source/blender/blenloader/intern/readfile.c | 13 ++++- source/blender/blenloader/intern/versioning_250.c | 2 + source/blender/makesdna/DNA_ID.h | 10 +++- source/blender/windowmanager/intern/wm_files.c | 7 +++ 8 files changed, 136 insertions(+), 23 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index cb86d54009b..27dd1e637f3 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -67,6 +67,14 @@ void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const ATTR_WARN_UNUSED_RESULT; void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1); +/* *** ID's session_uuid management. *** */ + +/* When an ID's uuid is of that value, it is unset/invalid (e.g. for runtime IDs, etc.). */ +#define MAIN_ID_SESSION_UUID_UNSET 0 + +void BKE_lib_libblock_session_uuid_reset(void); +void BKE_lib_libblock_session_uuid_ensure(struct ID *id); + void *BKE_id_new(struct Main *bmain, const short type, const char *name); void *BKE_id_new_nomain(const short type, const char *name); diff --git a/source/blender/blenkernel/BKE_main_idmap.h b/source/blender/blenkernel/BKE_main_idmap.h index a68d27a7882..e392b7db60e 100644 --- a/source/blender/blenkernel/BKE_main_idmap.h +++ b/source/blender/blenkernel/BKE_main_idmap.h @@ -40,22 +40,32 @@ struct ID; struct IDNameLib_Map; struct Main; +enum { + MAIN_IDMAP_TYPE_NAME = 1 << 0, + MAIN_IDMAP_TYPE_UUID = 1 << 1, +}; + struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain, const bool create_valid_ids_set, - struct Main *old_bmain) ATTR_WARN_UNUSED_RESULT + struct Main *old_bmain, + const int idmap_types) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); void BKE_main_idmap_destroy(struct IDNameLib_Map *id_typemap) ATTR_NONNULL(); struct Main *BKE_main_idmap_main_get(struct IDNameLib_Map *id_typemap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -struct ID *BKE_main_idmap_lookup(struct IDNameLib_Map *id_typemap, - short id_type, - const char *name, - const struct Library *lib) ATTR_WARN_UNUSED_RESULT +struct ID *BKE_main_idmap_lookup_name(struct IDNameLib_Map *id_typemap, + short id_type, + const char *name, + const struct Library *lib) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 3); struct ID *BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_typemap, const struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); +struct ID *BKE_main_idmap_lookup_uuid(struct IDNameLib_Map *id_typemap, + const uint session_uuid) ATTR_WARN_UNUSED_RESULT + ATTR_NONNULL(1); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 416de844691..92e9a7c6c79 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -1027,6 +1027,8 @@ void BKE_libblock_management_main_add(Main *bmain, void *idv) id->tag &= ~(LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT); bmain->is_memfile_undo_written = false; BKE_main_unlock(bmain); + + BKE_lib_libblock_session_uuid_ensure(id); } /** Remove a data-block from given main (set it to 'NO_MAIN' status). */ @@ -1313,6 +1315,8 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl /* alphabetic insertion: is in new_id */ BKE_main_unlock(bmain); + BKE_lib_libblock_session_uuid_ensure(id); + /* TODO to be removed from here! */ if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) { DEG_id_type_tag(bmain, type); @@ -1456,6 +1460,33 @@ void BKE_libblock_init_empty(ID *id) } } +/* ********** ID session-wise UUID management. ********** */ +static uint global_session_uuid = 0; + +/** Reset the session-wise uuid counter (used when reading a new file e.g.). */ +void BKE_lib_libblock_session_uuid_reset() +{ + global_session_uuid = 0; +} + +/** + * Generate a session-wise uuid for the given \a id. + * + * \note "session-wise" here means while editing a given .blend file. Once a new .blend file is + * loaded or created, undo history is cleared/reset, and so is the uuid counter. + */ +void BKE_lib_libblock_session_uuid_ensure(ID *id) +{ + if (id->session_uuid == MAIN_ID_SESSION_UUID_UNSET) { + id->session_uuid = atomic_add_and_fetch_uint32(&global_session_uuid, 1); + /* In case overflow happens, still assign a valid ID. This way opening files many times works + * correctly. */ + if (UNLIKELY(id->session_uuid == MAIN_ID_SESSION_UUID_UNSET)) { + id->session_uuid = atomic_add_and_fetch_uint32(&global_session_uuid, 1); + } + } +} + /** * Generic helper to create a new empty data-block of given type in given \a bmain database. * diff --git a/source/blender/blenkernel/intern/main_idmap.c b/source/blender/blenkernel/intern/main_idmap.c index a210961b212..26eb0b681a1 100644 --- a/source/blender/blenkernel/intern/main_idmap.c +++ b/source/blender/blenkernel/intern/main_idmap.c @@ -26,6 +26,7 @@ #include "DNA_ID.h" #include "BKE_idcode.h" +#include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_main_idmap.h" /* own include */ @@ -65,16 +66,20 @@ struct IDNameLib_TypeMap { */ struct IDNameLib_Map { struct IDNameLib_TypeMap type_maps[MAX_LIBARRAY]; + struct GHash *uuid_map; struct Main *bmain; struct GSet *valid_id_pointers; + int idmap_types; }; static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id_map, short id_type) { - for (int i = 0; i < MAX_LIBARRAY; i++) { - if (id_map->type_maps[i].id_type == id_type) { - return &id_map->type_maps[i]; + if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) { + for (int i = 0; i < MAX_LIBARRAY; i++) { + if (id_map->type_maps[i].id_type == id_type) { + return &id_map->type_maps[i]; + } } } return NULL; @@ -94,9 +99,12 @@ static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id */ struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain, const bool create_valid_ids_set, - struct Main *old_bmain) + struct Main *old_bmain, + const int idmap_types) { struct IDNameLib_Map *id_map = MEM_mallocN(sizeof(*id_map), __func__); + id_map->bmain = bmain; + id_map->idmap_types = idmap_types; int index = 0; while (index < MAX_LIBARRAY) { @@ -107,7 +115,22 @@ struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain, } BLI_assert(index == MAX_LIBARRAY); - id_map->bmain = bmain; + if (idmap_types & MAIN_IDMAP_TYPE_UUID) { + ID *id; + id_map->uuid_map = BLI_ghash_int_new(__func__); + FOREACH_MAIN_ID_BEGIN (bmain, id) { + BLI_assert(id->session_uuid != MAIN_ID_SESSION_UUID_UNSET); + void **id_ptr_v; + const bool existing_key = BLI_ghash_ensure_p( + id_map->uuid_map, POINTER_FROM_UINT(id->session_uuid), &id_ptr_v); + BLI_assert(existing_key == false); + *id_ptr_v = id; + } + FOREACH_MAIN_ID_END; + } + else { + id_map->uuid_map = NULL; + } if (create_valid_ids_set) { id_map->valid_id_pointers = BKE_main_gset_create(bmain, NULL); @@ -144,10 +167,10 @@ static bool idkey_cmp(const void *a, const void *b) return strcmp(idkey_a->name, idkey_b->name) || (idkey_a->lib != idkey_b->lib); } -ID *BKE_main_idmap_lookup(struct IDNameLib_Map *id_map, - short id_type, - const char *name, - const Library *lib) +ID *BKE_main_idmap_lookup_name(struct IDNameLib_Map *id_map, + short id_type, + const char *name, + const Library *lib) { struct IDNameLib_TypeMap *type_map = main_idmap_from_idcode(id_map, id_type); @@ -188,21 +211,34 @@ ID *BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_map, const ID *id) * when trying to get ID name). */ if (id_map->valid_id_pointers == NULL || BLI_gset_haskey(id_map->valid_id_pointers, id)) { - return BKE_main_idmap_lookup(id_map, GS(id->name), id->name + 2, id->lib); + return BKE_main_idmap_lookup_name(id_map, GS(id->name), id->name + 2, id->lib); + } + return NULL; +} + +ID *BKE_main_idmap_lookup_uuid(struct IDNameLib_Map *id_map, const uint session_uuid) +{ + if (id_map->idmap_types & MAIN_IDMAP_TYPE_UUID) { + return BLI_ghash_lookup(id_map->uuid_map, POINTER_FROM_UINT(session_uuid)); } return NULL; } void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map) { - struct IDNameLib_TypeMap *type_map = id_map->type_maps; - for (int i = 0; i < MAX_LIBARRAY; i++, type_map++) { - if (type_map->map) { - BLI_ghash_free(type_map->map, NULL, NULL); - type_map->map = NULL; - MEM_freeN(type_map->keys); + if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) { + struct IDNameLib_TypeMap *type_map = id_map->type_maps; + for (int i = 0; i < MAX_LIBARRAY; i++, type_map++) { + if (type_map->map) { + BLI_ghash_free(type_map->map, NULL, NULL); + type_map->map = NULL; + MEM_freeN(type_map->keys); + } } } + if (id_map->idmap_types & MAIN_IDMAP_TYPE_UUID) { + BLI_ghash_free(id_map->uuid_map, NULL, NULL); + } if (id_map->valid_id_pointers != NULL) { BLI_gset_free(id_map->valid_id_pointers, NULL); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 3107de38ff7..4d46435eea0 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -8056,7 +8056,8 @@ void blo_lib_link_restore(Main *oldmain, Scene *curscene, ViewLayer *cur_view_layer) { - struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain, true, oldmain); + struct IDNameLib_Map *id_map = BKE_main_idmap_create( + newmain, true, oldmain, MAIN_IDMAP_TYPE_NAME); for (WorkSpace *workspace = newmain->workspaces.first; workspace; workspace = workspace->id.next) { @@ -8801,6 +8802,8 @@ static ID *create_placeholder(Main *mainvar, const short idcode, const char *idn BLI_addtail(lb, ph_id); id_sort_by_name(lb, ph_id, NULL); + BKE_lib_libblock_session_uuid_ensure(ph_id); + return ph_id; } @@ -9013,6 +9016,14 @@ static BHead *read_libblock(FileData *fd, oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); BLI_addtail(lb, id); + + if (fd->memfile == NULL) { + /* When actually reading a file , we do want to reset/re-generate session uuids. + * In unod case, we want to re-use existing ones. */ + id->session_uuid = MAIN_ID_SESSION_UUID_UNSET; + } + + BKE_lib_libblock_session_uuid_ensure(id); } else { /* unknown ID type */ diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index a4b51f91be4..cf4924eeb6d 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -446,6 +446,8 @@ static void versions_gpencil_add_main(ListBase *lb, ID *id, const char *name) BKE_id_new_name_validate(lb, id, name); /* alphabetic insertion: is in BKE_id_new_name_validate */ + BKE_lib_libblock_session_uuid_ensure(id); + if (G.debug & G_DEBUG) { printf("Converted GPencil to ID: %s\n", id->name + 2); } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 89af705d5ed..3ac93a96661 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -31,6 +31,8 @@ extern "C" { #endif +#include "DNA_defs.h" + struct FileData; struct GHash; struct GPUTexture; @@ -243,7 +245,13 @@ typedef struct ID { int us; int icon_id; int recalc; - char _pad[4]; + + /** + * A session-wide unique identifier for a given ID, that remain the same across potential + * re-allocations (e.g. due to undo/redo steps). + */ + unsigned int session_uuid; + IDProperty *properties; /** Reference linked ID which this one overrides. */ diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index dae6f62319d..2dcacc3dc30 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -77,6 +77,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_idprop.h" +#include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_main.h" #include "BKE_packedFile.h" @@ -611,6 +612,9 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) UI_view2d_zoom_cache_reset(); + /* Reset session-wise ID UUID counter. */ + BKE_lib_libblock_session_uuid_reset(); + /* first try to append data from exotic file formats... */ /* it throws error box when file doesn't exist and returns -1 */ /* note; it should set some error message somewhere... (ton) */ @@ -917,6 +921,9 @@ void wm_homefile_read(bContext *C, } } + /* Reset session-wise ID UUID counter. */ + BKE_lib_libblock_session_uuid_reset(); + if (!use_factory_settings || (filepath_startup[0] != '\0')) { if (BLI_access(filepath_startup, R_OK) == 0) { success = BKE_blendfile_read(C, -- cgit v1.2.3