.. include:: ../disclaimer-zh_CN.rst :Original: Documentation/core-api/assoc_array.rst :翻译: å¸å»¶è…¾ Yanteng Si <siyanteng@loongson.cn> :æ ¡è¯‘: .. _cn_core-api_assoc_array: ================== 通用关è”数组的实现 ================== 简介 ==== 这个关è”数组的实现是一个具有以下属性的对象容器: 1. 对象是ä¸é€æ˜Žçš„指针。该实现ä¸å…³å¿ƒå®ƒä»¬æŒ‡å‘哪里(如果有的è¯ï¼‰æˆ–它们指å‘什么(如果有的 è¯ï¼‰ã€‚ .. note:: 指å‘对象的指针 *å¿…é¡»* 在最å°æœ‰æ•ˆä½ä¸ºé›¶ã€‚ 2. 对象ä¸éœ€è¦åŒ…å«ä¾›æ•°ç»„使用的链接å—。这å…许一个对象åŒæ—¶ä½äºŽå¤šä¸ªæ•°ç»„ä¸ã€‚相å,数组是 由指å‘对象的元数æ®å—组æˆçš„。 3. 对象需è¦ç´¢å¼•é”®æ¥å®šä½å®ƒä»¬åœ¨é˜µåˆ—ä¸çš„ä½ç½®ã€‚ 4. 索引键必须是唯一的。æ’入一个与已ç»åœ¨æ•°ç»„ä¸çš„且具有相åŒé”®å€¼çš„对象将å–代旧的对象。 5. 索引键å¯ä»¥æ˜¯ä»»ä½•é•¿åº¦ï¼Œä¹Ÿå¯ä»¥æ˜¯ä¸åŒçš„长度。 6. 索引键应该在早期就对长度进行编ç ,å³åœ¨ä»»ä½•ç”±äºŽé•¿åº¦å¼•èµ·çš„å˜åŒ–出现之å‰ã€‚ 7. 索引键å¯ä»¥åŒ…括一个哈希值,以便将对象分散到整个数组ä¸ã€‚ 8. 该数组å¯ä»¥è¿ä»£ã€‚对象ä¸ä¸€å®šä¼šæŒ‰ç´¢å¼•é”®çš„顺åºå‡ºçŽ°ã€‚ 9. 数组å¯ä»¥åœ¨è¢«ä¿®æ”¹çš„时候进行è¿ä»£ï¼Œåªè¦RCU的读é”被è¿ä»£å™¨æŒæœ‰ã€‚然而,请注æ„,在这ç§æƒ… 况下,一些对象å¯èƒ½ä¼šè¢«çœ‹åˆ°ä¸æ¢ä¸€æ¬¡ã€‚如果这是个问题,è¿ä»£å™¨åº”该é”定以防æ¢ä¿®æ”¹ã€‚然 而,除éžåˆ 除,å¦åˆ™å¯¹è±¡ä¸ä¼šè¢«é”™è¿‡ã€‚ 10. 数组ä¸çš„对象å¯ä»¥é€šè¿‡å…¶ç´¢å¼•é”®è¿›è¡ŒæŸ¥è¯¢ã€‚ 11. 当数组被修改时,对象å¯ä»¥è¢«æŸ¥è¯¢ï¼Œå‰æ是进行查询的线程æŒæœ‰RCU的读é”。 该实现在内部使用了一棵由16个指针节点组æˆçš„æ ‘ï¼Œè¿™äº›èŠ‚ç‚¹åœ¨æ¯ä¸€å±‚都由索引键的å°æ•°ç‚¹è¿›è¡Œç´¢ 引,其方å¼ä¸ŽåŸºæ•°æ ‘相åŒã€‚为了æ高内å˜æ•ˆçŽ‡ï¼Œå¯ä»¥æ”¾ç½®å¿«æ·é”®ï¼Œä»¥è·³è¿‡æœ¬æ¥æ˜¯ä¸€ç³»åˆ—å•å 节点的地 方。æ¤å¤–,节点将å¶å对象指针打包到节点的空闲空间ä¸ï¼Œè€Œä¸æ˜¯åšä¸€ä¸ªé¢å¤–的分支,直到有对象 需è¦è¢«æ·»åŠ 到一个完整的节点ä¸ã€‚ 公用API ======= 公用APIå¯ä»¥åœ¨ ``<linux/assoc_array.h>`` ä¸æ‰¾åˆ°ã€‚å…³è”æ•°ç»„çš„æ ¹æ˜¯ä»¥ä¸‹ç»“æž„:: struct assoc_array { ... }; 该代ç 是通过å¯ç”¨ ``CONFIG_ASSOCIATIVE_ARRAY`` æ¥é€‰æ‹©çš„,以:: ./script/config -e ASSOCIATIVE_ARRAY 编辑脚本 -------- æ’å…¥å’Œåˆ é™¤åŠŸèƒ½ä¼šäº§ç”Ÿä¸€ä¸ªâ€œç¼–è¾‘è„šæœ¬â€ï¼Œä»¥åŽå¯ä»¥åº”用这个脚本æ¥å®žçŽ°æ›´æ”¹ï¼Œè€Œä¸ä¼šé€ æˆ ``ENOMEM`` 风险。这ä¿ç•™äº†å°†è¢«å®‰è£…åœ¨å†…éƒ¨æ ‘ä¸çš„预分é…的元数æ®å—ï¼Œå¹¶è·Ÿè¸ªåº”ç”¨è„šæœ¬æ—¶å°†ä»Žæ ‘ä¸åˆ 除的元数 æ®å—。 在脚本应用åŽï¼Œè¿™ä¹Ÿè¢«ç”¨æ¥è·Ÿè¸ªæ»å—å’Œæ»å¯¹è±¡ï¼Œä»¥ä¾¿ä»¥åŽå¯ä»¥é‡Šæ”¾å®ƒä»¬ã€‚释放是在RCU宽é™æœŸè¿‡åŽ 进行的--å› æ¤å…许访问功能在RCU读é”下进行。 脚本在API之外显示为一个类型为:: struct assoc_array_edit; 有两个处ç†è„šæœ¬çš„功能: 1. 应用一个编辑脚本:: void assoc_array_apply_edit(struct assoc_array_edit *edit); 这将执行编辑功能,æ’值å„ç§å†™å±éšœï¼Œä»¥å…许在RCU读é”下的访问继ç»è¿›è¡Œã€‚然åŽï¼Œç¼–辑脚本将被 ä¼ é€’ç»™ ``call_rcu()`` ,以释放它和它所指å‘的任何æ»çš„东西。 2. Cancel an edit script:: void assoc_array_cancel_edit(struct assoc_array_edit *edit); 这将立å³é‡Šæ”¾ç¼–辑脚本和所有预分é…的内å˜ã€‚如果这是为了æ’入,新的对象ä¸ä¼šè¢«è¿™ä¸ªå‡½æ•°é‡Šæ”¾ï¼Œ 而是必须由调用者释放。 这些函数ä¿è¯ä¸ä¼šå¤±è´¥ã€‚ æ“作表 ------ å„ç§åŠŸèƒ½é‡‡ç”¨äº†ä¸€ä¸ªæ“作表:: struct assoc_array_ops { ... }; 这指出了一些方法,所有这些方法都需è¦æä¾›: 1. 从调用者数æ®ä¸èŽ·å–索引键的一个å—:: unsigned long (*get_key_chunk)(const void *index_key, int level); 这应该返回一个由调用者æ供的索引键的å—,从levelå‚数给出的 *比特* ä½ç½®å¼€å§‹ã€‚levelå‚æ•°å°† 是 ``ASSOC_ARRAY_KEY_CHUNK_SIZE`` çš„å€æ•°ï¼Œè¯¥å‡½æ•°åº”返回 ``ASSOC_ARRAY_KEY_CHUNK_SIZE`` ä½ã€‚ä¸å¯èƒ½å‡ºçŽ°é”™è¯¯ã€‚ 2. 获å–一个对象的索引键的一个å—:: unsigned long (*get_object_key_chunk)(const void *object, int level); å’Œå‰é¢çš„å‡½æ•°ä¸€æ ·ï¼Œä½†æ˜¯ä»Žæ•°ç»„ä¸çš„一个对象而ä¸æ˜¯ä»Žè°ƒç”¨è€…æ供的索引键ä¸èŽ·å–æ•°æ®ã€‚ 3. 看看这是å¦æ˜¯æˆ‘们è¦æ‰¾çš„对象:: bool (*compare_object)(const void *object, const void *index_key); 将对象与一个索引键进行比较,如果匹é…则返回 ``true`` ,ä¸åŒ¹é…则返回 ``false`` 。 4. 对两个对象的索引键进行比较:: int (*diff_objects)(const void *object, const void *index_key); 返回指定对象的索引键与给定索引键ä¸åŒçš„比特ä½ç½®ï¼Œå¦‚果它们相åŒï¼Œåˆ™è¿”回-1。 5. 释放一个对象:: void (*free_object)(void *object); 释放指定的对象。注æ„,这å¯èƒ½æ˜¯åœ¨è°ƒç”¨ ``assoc_array_apply_edit()`` åŽçš„一个RCU宽é™æœŸå†… 调用的,所以在模å—å¸è½½æ—¶å¯èƒ½éœ€è¦ ``synchronize_rcu()`` 。 æ“控函数 -------- 有一些函数用于æ“控关è”数组: 1. åˆå§‹åŒ–一个关è”数组:: void assoc_array_init(struct assoc_array *array); 这将åˆå§‹åŒ–一个关è”数组的基础结构。它ä¸ä¼šå¤±è´¥ã€‚ 2. 在一个关è”数组ä¸æ’å…¥/替æ¢ä¸€ä¸ªå¯¹è±¡:: struct assoc_array_edit * assoc_array_insert(struct assoc_array *array, const struct assoc_array_ops *ops, const void *index_key, void *object); 这将把给定的对象æ’入数组ä¸ã€‚注æ„,指针的最å°æœ‰æ•ˆä½å¿…须是0ï¼Œå› ä¸ºå®ƒè¢«ç”¨æ¥åœ¨å†…éƒ¨æ ‡è®°æŒ‡é’ˆçš„ç±» 型。 如果该键已ç»å˜åœ¨ä¸€ä¸ªå¯¹è±¡ï¼Œé‚£ä¹ˆå®ƒå°†è¢«æ–°çš„对象所å–代,旧的对象将被自动释放。 ``index_key`` å‚数应æŒæœ‰ç´¢å¼•é”®ä¿¡æ¯ï¼Œå¹¶åœ¨è°ƒç”¨OPP表ä¸çš„æ–¹æ³•æ—¶ä¼ é€’ç»™å®ƒä»¬ã€‚ 这个函数ä¸å¯¹æ•°ç»„本身åšä»»ä½•æ”¹åŠ¨ï¼Œè€Œæ˜¯è¿”回一个必须应用的编辑脚本。如果出现内å˜ä¸è¶³çš„错误,会 返回 ``-ENOMEM`` 。 调用者应专门é”定数组的其他修改器。 3. 从一个关è”数组ä¸åˆ 除一个对象:: struct assoc_array_edit * assoc_array_delete(struct assoc_array *array, const struct assoc_array_ops *ops, const void *index_key); 这将从数组ä¸åˆ 除一个符åˆæŒ‡å®šæ•°æ®çš„对象。 ``index_key`` å‚数应æŒæœ‰ç´¢å¼•é”®ä¿¡æ¯ï¼Œå¹¶åœ¨è°ƒç”¨OPP表ä¸çš„æ–¹æ³•æ—¶ä¼ é€’ç»™å®ƒä»¬ã€‚ 这个函数ä¸å¯¹æ•°ç»„本身åšä»»ä½•æ”¹åŠ¨ï¼Œè€Œæ˜¯è¿”回一个必须应用的编辑脚本。 ``-ENOMEM`` 在出现内å˜ä¸è¶³ 的错误时返回。如果在数组ä¸æ²¡æœ‰æ‰¾åˆ°æŒ‡å®šçš„对象,将返回 ``NULL`` 。 调用者应该对数组的其他修改者进行专门é”定。 4. 从一个关è”数组ä¸åˆ 除所有对象:: struct assoc_array_edit * assoc_array_clear(struct assoc_array *array, const struct assoc_array_ops *ops); è¿™ä¸ªå‡½æ•°åˆ é™¤äº†ä¸€ä¸ªå…³è”数组ä¸çš„所有对象,使其完全为空。 这个函数没有对数组本身åšä»»ä½•æ”¹åŠ¨ï¼Œè€Œæ˜¯è¿”回一个必须应用的编辑脚本。如果出现内å˜ä¸è¶³ 的错误,则返回 ``-ENOMEM`` 。 调用者应专门é”定数组的其他修改者。 5. 销æ¯ä¸€ä¸ªå…³è”æ•°ç»„ï¼Œåˆ é™¤æ‰€æœ‰å¯¹è±¡:: void assoc_array_destroy(struct assoc_array *array, const struct assoc_array_ops *ops); è¿™å°†ç ´åå…³è”数组的内容,使其完全为空。在这个函数销æ¯æ•°ç»„çš„åŒæ—¶ï¼Œä¸å…许å¦ä¸€ä¸ªçº¿ç¨‹åœ¨RCUè¯»é” ä¸‹éåŽ†æ•°ç»„ï¼Œå› ä¸ºåœ¨å†…å˜é‡Šæ”¾æ—¶ä¸æ‰§è¡ŒRCU延迟,这需è¦åˆ†é…内å˜ã€‚ 调用者应该专门针对数组的其他修改者和访问者进行é”定。 6. 垃圾回收一个关è”数组:: int assoc_array_gc(struct assoc_array *array, const struct assoc_array_ops *ops, bool (*iterator)(void *object, void *iterator_data), void *iterator_data); 这是对一个关è”数组ä¸çš„对象进行è¿ä»£ï¼Œå¹¶å°†æ¯ä¸ªå¯¹è±¡ä¼ 递给 ``iterator()`` 。如果 ``iterator()`` 返回 true,该对象被ä¿ç•™ã€‚如果它返回 ``false`` ,该对象将被释放。如果 ``iterator()`` 函数返回 ``true`` ,它必须 在返回之å‰å¯¹è¯¥å¯¹è±¡è¿›è¡Œé€‚当的 ``refcount`` 递增。 如果å¯èƒ½çš„è¯ï¼Œå†…éƒ¨æ ‘å°†è¢«æ‰“åŒ…ä¸‹æ¥ï¼Œä½œä¸ºè¿ä»£çš„一部分,以å‡å°‘å…¶ä¸çš„节点数é‡ã€‚ ``iterator_data`` è¢«ç›´æŽ¥ä¼ é€’ç»™ ``iterator()`` ,å¦åˆ™ä¼šè¢«å‡½æ•°å¿½ç•¥ã€‚ 如果æˆåŠŸï¼Œè¯¥å‡½æ•°å°†è¿”回 ``0`` ,如果没有足够的内å˜ï¼Œåˆ™è¿”回 ``-ENOMEM`` 。 在这个函数执行过程ä¸ï¼Œå…¶ä»–线程有å¯èƒ½åœ¨RCU读é”下è¿ä»£æˆ–æœç´¢é˜µåˆ—。调用者应该专门针对数组的其他 修改者进行é”定。 访问函数 -------- 有两个函数用于访问一个关è”数组: 1. é历一个关è”数组ä¸çš„所有对象:: int assoc_array_iterate(const struct assoc_array *array, int (*iterator)(const void *object, void *iterator_data), void *iterator_data); 这将数组ä¸çš„æ¯ä¸ªå¯¹è±¡ä¼ 递给è¿ä»£å™¨å›žè°ƒå‡½æ•°ã€‚ ``iterator_data`` 是该函数的ç§æœ‰æ•°æ®ã€‚ 在数组被修改的åŒæ—¶ï¼Œå¯ä»¥åœ¨æ•°ç»„上使用这个方法,å‰æ是RCU读é”被æŒæœ‰ã€‚在这ç§æƒ…况下,è¿ä»£å‡½æ•°æœ‰ å¯èƒ½ä¸¤æ¬¡çœ‹åˆ°æŸäº›å¯¹è±¡ã€‚如果这是个问题,那么修改应该被é”定。然而,è¿ä»£ç®—法ä¸åº”该错过任何对象。 如果数组ä¸æ²¡æœ‰å¯¹è±¡ï¼Œè¯¥å‡½æ•°å°†è¿”回 ``0`` ,å¦åˆ™å°†è¿”回最åŽä¸€æ¬¡è°ƒç”¨çš„è¿ä»£å™¨å‡½æ•°çš„结果。如果对è¿ä»£å‡½æ•° 的任何调用导致éžé›¶è¿”回,è¿ä»£ç«‹å³åœæ¢ã€‚ 2. 在一个关è”数组ä¸å¯»æ‰¾ä¸€ä¸ªå¯¹è±¡:: void *assoc_array_find(const struct assoc_array *array, const struct assoc_array_ops *ops, const void *index_key); è¿™å°†ç›´æŽ¥ç©¿è¿‡æ•°ç»„çš„å†…éƒ¨æ ‘ï¼Œåˆ°è¾¾ç´¢å¼•é”®æ‰€æŒ‡å®šçš„å¯¹è±¡ã€‚ 这个函数å¯ä»¥åœ¨ä¿®æ”¹æ•°ç»„çš„åŒæ—¶ç”¨åœ¨æ•°ç»„上,å‰æ是RCU读é”被æŒæœ‰ã€‚ 如果找到对象,该函数将返回对象(并将 ``*_type`` 设置为对象的类型),如果没有找到对象,将返回 ``NULL`` 。 ç´¢å¼•é”®å½¢å¼ ---------- 索引键å¯ä»¥æ˜¯ä»»ä½•å½¢å¼çš„,但是由于算法没有被告知键有多长,所以强烈建议在任何由于长度而产生的å˜åŒ– 对比较产生影å“之å‰ï¼Œç´¢å¼•é”®åº”该很早就包括其长度。 这将导致具有ä¸åŒé•¿åº¦é”®çš„å¶å相互分散,而具有相åŒé•¿åº¦é”®çš„å¶å则èšé›†åœ¨ä¸€èµ·ã€‚ 我们还建议索引键以键的其余部分的哈希值开始,以最大é™åº¦åœ°æ高整个键空间的散布情况。 åˆ†æ•£æ€§è¶Šå¥½ï¼Œå†…éƒ¨æ ‘å°±è¶Šå®½ï¼Œè¶Šä½Žã€‚ 分散性差并ä¸æ˜¯ä¸€ä¸ªå¤ªå¤§çš„é—®é¢˜ï¼Œå› ä¸ºæœ‰å¿«æ·é”®ï¼ŒèŠ‚点å¯ä»¥åŒ…å«å¶å和元数æ®æŒ‡é’ˆçš„æ··åˆç‰©ã€‚ 索引键是以机器å—çš„å—状æ¥è¯»å–的。æ¯ä¸ªå—被细分为æ¯å±‚一个nibble(4比特),所以在32ä½CPU上这适åˆ8层, 在64ä½CPU上适åˆ16层。除éžæ•£å¸ƒæƒ…况真的很差,å¦åˆ™ä¸å¤ªå¯èƒ½æœ‰è¶…过一个å—的任何特定索引键需è¦è¢«ä½¿ç”¨ã€‚ 内部工作机制 ============ å…³è”数组数æ®ç»“æž„æœ‰ä¸€ä¸ªå†…éƒ¨æ ‘ã€‚è¿™ä¸ªæ ‘ç”±ä¸¤ç§ç±»åž‹çš„元数æ®å—æž„æˆï¼šèŠ‚点和快æ·é”®ã€‚ 一个节点是一个槽的数组。æ¯ä¸ªæ§½å¯ä»¥åŒ…å«ä»¥ä¸‹å››ç§ä¸œè¥¿ä¹‹ä¸€: * 一个NULL的指针,表示槽是空的。 * 一个指å‘对象(å¶å)的指针。 * 一个指å‘下一级节点的指针。 * 一个指å‘å¿«æ·é”®çš„指针。 åŸºæœ¬çš„å†…éƒ¨æ ‘å½¢å¸ƒå±€ ------------------ æš‚æ—¶ä¸è€ƒè™‘å¿«æ·é”®ï¼ŒèŠ‚点形æˆä¸€ä¸ªå¤šçº§æ ‘ã€‚ç´¢å¼•é”®ç©ºé—´è¢«æ ‘ä¸Šçš„èŠ‚ç‚¹ä¸¥æ ¼ç»†åˆ†ï¼ŒèŠ‚ç‚¹å‡ºçŽ°åœ¨å›ºå®šçš„å±‚æ¬¡ä¸Šã€‚ä¾‹å¦‚:: Level: 0 1 2 3 =============== =============== =============== =============== NODE D NODE B NODE C +------>+---+ +------>+---+ +------>+---+ | | 0 | NODE A | | 0 | | | 0 | | +---+ +---+ | +---+ | +---+ | : : | 0 | | : : | : : | +---+ +---+ | +---+ | +---+ | | f | | 1 |---+ | 3 |---+ | 7 |---+ +---+ +---+ +---+ +---+ : : : : | 8 |---+ +---+ +---+ +---+ | NODE E | e |---+ | f | : : +------>+---+ +---+ | +---+ +---+ | 0 | | f | | | f | +---+ +---+ | +---+ : : | NODE F +---+ +------>+---+ | f | | 0 | NODE G +---+ +---+ +------>+---+ : : | | 0 | +---+ | +---+ | 6 |---+ : : +---+ +---+ : : | f | +---+ +---+ | f | +---+ 在上述例åä¸ï¼Œæœ‰7个节点(A-G),æ¯ä¸ªèŠ‚点有16个槽(0-f)。å‡è®¾æ ‘上没有其他元数æ®èŠ‚点,那么密钥空间 æ˜¯è¿™æ ·åˆ’åˆ†çš„:: KEY PREFIX NODE ========== ==== 137* D 138* E 13[0-69-f]* C 1[0-24-f]* B e6* G e[0-57-f]* F [02-df]* A å› æ¤ï¼Œä¾‹å¦‚,具有以下示例索引键的键将在适当的节点ä¸è¢«æ‰¾åˆ°:: INDEX KEY PREFIX NODE =============== ======= ==== 13694892892489 13 C 13795289025897 137 D 13889dde88793 138 E 138bbb89003093 138 E 1394879524789 12 C 1458952489 1 B 9431809de993ba - A b4542910809cd - A e5284310def98 e F e68428974237 e6 G e7fffcbd443 e F f3842239082 - A 为了节çœå†…å˜ï¼Œå¦‚果一个节点å¯ä»¥å®¹çº³å®ƒçš„那部分键空间ä¸çš„所有å¶å,那么这个节点将有所有这些å¶åï¼Œè€Œä¸ ä¼šæœ‰ä»»ä½•å…ƒæ•°æ®æŒ‡é’ˆâ€”—å³ä½¿å…¶ä¸ä¸€äº›å¶å想在åŒä¸€ä¸ªæ§½ä¸ã€‚ 一个节点å¯ä»¥åŒ…å«å¶å和元数æ®æŒ‡é’ˆçš„异质性混åˆã€‚元数æ®æŒ‡é’ˆå¿…须在与它们的关键空间的细分相匹é…的槽ä¸ã€‚ å¶åå¯ä»¥åœ¨ä»»ä½•æ²¡æœ‰è¢«å…ƒæ•°æ®æŒ‡é’ˆå æ®çš„槽ä¸ã€‚ä¿è¯ä¸€ä¸ªèŠ‚点ä¸æ²¡æœ‰ä¸€ä¸ªå¶å会与元数æ®æŒ‡é’ˆå æ®çš„槽相匹é…。 如果元数æ®æŒ‡é’ˆåœ¨é‚£é‡Œï¼Œä»»ä½•é”®ä¸Žå…ƒæ•°æ®é”®å‰ç¼€ç›¸åŒ¹é…çš„å¶å¿…须在元数æ®æŒ‡é’ˆæŒ‡å‘çš„åæ ‘ä¸ã€‚ 在上é¢çš„索引键的例å列表ä¸ï¼ŒèŠ‚点A将包å«:: SLOT CONTENT INDEX KEY (PREFIX) ==== =============== ================== 1 PTR TO NODE B 1* any LEAF 9431809de993ba any LEAF b4542910809cd e PTR TO NODE F e* any LEAF f3842239082 和节点B:: 3 PTR TO NODE C 13* any LEAF 1458952489 å¿«æ·é”® --------- å¿«æ·é”®æ˜¯è·³è¿‡ä¸€å—键空间的元数æ®è®°å½•ã€‚å¿«æ·é”®æ˜¯ä¸€ç³»åˆ—通过层次上å‡çš„å•å 节点的替代物。快æ·é”®çš„å˜åœ¨æ˜¯ 为了节çœå†…å˜å’ŒåŠ å¿«é历速度。 æ ‘çš„æ ¹éƒ¨æœ‰å¯èƒ½æ˜¯ä¸€ä¸ªå¿«æ·é”®â€”â€”æ¯”å¦‚è¯´ï¼Œæ ‘è‡³å°‘åŒ…å«17个节点,都有键å‰ç¼€ ``1111`` 。æ’入算法将æ’入一个快æ·é”®ï¼Œ 以å•æ¬¡è·³è¿‡ ``1111`` çš„é”®ä½ï¼Œå¹¶åˆ°è¾¾ç¬¬å››å±‚,在这里,这些键ä½å®žé™…上å˜å¾—ä¸åŒã€‚ 拆分和åˆå¹¶èŠ‚点 ------------------------------ æ¯ä¸ªèŠ‚点的最大容é‡ä¸º16个å¶å和元数æ®æŒ‡é’ˆã€‚如果æ’入算法å‘现它æ£è¯•å›¾å°†ä¸€ä¸ªç¬¬17个对象æ’入到一个节点ä¸ï¼Œ 该节点将被拆分,使得至少两个在该层有一个共åŒçš„关键段的å¶å最终在一个å•ç‹¬çš„节点ä¸ï¼Œè¯¥å…±åŒçš„å…³é”®æ®µçš„æ ¹ 在该槽上。 如果一个完整的节点ä¸çš„å¶å和被æ’入的å¶åè¶³å¤Ÿç›¸ä¼¼ï¼Œé‚£ä¹ˆå°±ä¼šåœ¨æ ‘ä¸æ’入一个快æ·é”®ã€‚ å½“æ ¹æ¤äºŽæŸä¸ªèŠ‚点的åæ ‘ä¸çš„对象数é‡ä¸‹é™åˆ°16个或更少时,那么该åæ ‘å°†è¢«åˆå¹¶æˆä¸€ä¸ªå•ç‹¬çš„节点——如果å¯èƒ½çš„ è¯ï¼Œè¿™å°†å‘æ ¹éƒ¨æ‰©æ•£ã€‚ éžé€’å½’å¼è¿ä»£ ------------ æ¯ä¸ªèŠ‚点和快æ·é”®éƒ½åŒ…å«ä¸€ä¸ªæŒ‡å‘其父节点的åŽç½®æŒ‡é’ˆï¼Œä»¥åŠè¯¥çˆ¶èŠ‚点ä¸æŒ‡å‘它的槽数。éžé€’å½’è¿ä»£ä½¿ç”¨è¿™äº›æ¥ é€šè¿‡æ ‘çš„æ ¹éƒ¨è¿›è¡Œï¼Œå‰å¾€çˆ¶èŠ‚点,槽N+1,以确ä¿åœ¨æ²¡æœ‰å †æ ˆçš„情况下å–得进展。 然而,åå‘指针使得åŒæ—¶æ”¹å˜å’Œè¿ä»£å˜å¾—很棘手。 åŒæ—¶æ”¹å˜å’Œè¿ä»£ -------------- 有一些情况需è¦è€ƒè™‘: 1. 简å•çš„æ’å…¥/替æ¢ã€‚这涉åŠåˆ°ç®€å•åœ°å°†ä¸€ä¸ªNULL或旧的匹é…å¶å的指针替æ¢ä¸ºå±éšœåŽçš„æ–°å¶å的指针。å¦åˆ™å…ƒæ•° æ®å—ä¸ä¼šæ”¹å˜ã€‚一个旧的å¶å直到RCU宽é™æœŸè¿‡åŽæ‰ä¼šè¢«é‡Šæ”¾ã€‚ 2. 简å•åˆ 除。这åªæ˜¯æ¶‰åŠåˆ°æ¸…除一个旧的匹é…å¶å。元数æ®å—ä¸ä¼šæœ‰å…¶ä»–å˜åŒ–。旧的å¶å直到RCU宽é™æœŸä¹‹åŽæ‰ä¼š 被释放。 3. æ’入,替æ¢æˆ‘们还没有进入的åæ ‘çš„ä¸€éƒ¨åˆ†ã€‚è¿™å¯èƒ½æ¶‰åŠåˆ°æ›¿æ¢è¯¥åæ ‘çš„ä¸€éƒ¨åˆ†â€”â€”ä½†è¿™ä¸ä¼šå½±å“è¿ä»£ï¼Œå› 为我们 还没有到达它的指针,而且祖先å—也ä¸ä¼šè¢«æ›¿æ¢ï¼ˆè¿™äº›å—的布局ä¸ä¼šæ”¹å˜ï¼‰ã€‚ 4. æ’入替æ¢äº†æˆ‘们æ£åœ¨å¤„ç†çš„节点。这ä¸æ˜¯ä¸€ä¸ªé—®é¢˜ï¼Œå› 为我们已ç»é€šè¿‡äº†é”šå®šæŒ‡é’ˆï¼Œç›´åˆ°æˆ‘们跟éšåŽé¢çš„æŒ‡é’ˆæ‰ ä¼šåˆ‡æ¢åˆ°æ–°çš„布局上——这时我们已ç»æ£€æŸ¥äº†è¢«æ›¿æ¢èŠ‚点的å¶å(在跟éšä»»ä½•å…ƒæ•°æ®æŒ‡é’ˆä¹‹å‰ï¼Œæˆ‘们会è¿ä»£ä¸€ä¸ªèŠ‚ 点的所有å¶å)。 然而,我们å¯èƒ½ä¼šé‡æ–°çœ‹åˆ°ä¸€äº›å¶å,这些å¶åå·²ç»è¢«åˆ†å‰²æˆä¸€ä¸ªæ–°çš„分支,而这个分支的ä½ç½®æ¯”我们之å‰çš„ä½ ç½®æ›´è¿œã€‚ 5. æ’入替æ¢äº†æˆ‘们æ£åœ¨å¤„ç†çš„ä¾èµ–分支的节点。这ä¸ä¼šå½±å“到我们,直到我们跟éšåŽé¢çš„指针。与(4)类似。 6. åˆ æŽ‰æˆ‘ä»¬ä¸‹é¢çš„一个分支。这ä¸ä¼šå½±å“æˆ‘ä»¬ï¼Œå› ä¸ºåœ¨æˆ‘ä»¬çœ‹åˆ°æ–°èŠ‚ç‚¹ä¹‹å‰ï¼Œå›žæº¯æŒ‡é’ˆä¼šè®©æˆ‘们回到新节点的父节 点。整个崩溃的åæ ‘è¢«æ‰”æŽ‰äº†ï¼Œæ²¡æœ‰ä»»ä½•å˜åŒ–——而且ä»ç„¶ä¼šåœ¨åŒä¸€ä¸ªæ§½ä¸Šç”Ÿæ ¹ï¼Œæ‰€ä»¥æˆ‘们ä¸åº”该第二次处ç†å®ƒï¼Œ å› ä¸ºæˆ‘ä»¬ä¼šå›žåˆ°æ§½+1。 .. note:: 在æŸäº›æƒ…况下,我们需è¦åŒæ—¶æ”¹å˜ä¸€ä¸ªèŠ‚点的父指针和父槽指针(比如说,我们在它之å‰æ’入了å¦ä¸€ä¸ªèŠ‚点, 并把它往上移了一层)。我们ä¸èƒ½åœ¨ä¸é”定读å–çš„æƒ…å†µä¸‹è¿™æ ·åšâ€”—所以我们必须åŒæ—¶æ›¿æ¢è¯¥èŠ‚点。 然而,当我们把一个快æ·é”®æ”¹æˆä¸€ä¸ªèŠ‚点时,这ä¸æ˜¯ä¸€ä¸ªé—®é¢˜ï¼Œå› 为快æ·é”®åªæœ‰ä¸€ä¸ªæ§½ï¼Œæ‰€ä»¥å½“å‘åŽé 历一个槽时,ä¸ä¼šä½¿ç”¨çˆ¶æ§½å·ã€‚è¿™æ„味ç€å…ˆæ”¹å˜æ§½ä½å·æ˜¯å¯ä»¥çš„——åªè¦ä½¿ç”¨é€‚当的å±éšœæ¥ç¡®ä¿çˆ¶æ§½ä½å·åœ¨åŽ 退指针之åŽè¢«è¯»å–。 过时的å—å’Œå¶å在RCU宽é™æœŸè¿‡åŽä¼šè¢«é‡Šæ”¾ï¼Œæ‰€ä»¥åªè¦ä»»ä½•è¿›è¡Œé历或è¿ä»£çš„人æŒæœ‰RCU读é”,旧的上层建ç‘å°±ä¸ åº”è¯¥åœ¨ä»–ä»¬èº«ä¸Šæ¶ˆå¤±ã€‚