# Improvements in Manticore Search 2.7: local indexes management

直到现在，资源共享都是通过读写锁来实现的。在高负载情况下，使用锁机制在尝试对索引进行修改时可能会遇到问题。为了解决这些问题，我们必须重新思考线程与索引之间的关系。

索引可能很大甚至非常大，它们在多个工作进程中共享。在多核 CPU 上，你可以同时发起许多查询，它们会分布在各个核心上，使用同一个索引。这很简单明了。然而，有时你需要更新索引。无缝切换在旧版 **fork** 工作进程中表现良好：我们只需加载新的索引文件，让正在运行的 fork 进程继续使用旧索引提供服务。在某一时刻，新查询会转向已加载新索引的 fork 进程。因此，服务不会出现延迟：你只需无缝地从旧索引切换到新索引。使用旧版本的进程会完成（或崩溃），最终旧索引会被释放。

在使用线程工作进程的情况下，采用的是简单的 **读写锁**（**shared-exclusive locks**）机制，其中多个共享工作进程（读取者）可以同时访问资源，但只有一个独占工作进程（写入者）可以修改它。因此，索引始终处于 **共享** 状态（供查询使用），或被 **锁定**（用于切换）。它们在开始时加载，在结束时释放。当进行切换时，一个线程加载新索引，但需要独占访问活动索引描述符。然而，查询工作进程具有共享访问权限，没有人会阻止它们获取新任务。这意味着在高负载情况下，你无法完成“无缝”切换，因为它的最后一步是原子性地将旧索引切换为新索引。

在 2.7 版本引入的新模型中，索引现在在各个线程之间独立存在，类似于旧版的 **fork** 情况，因为它们现在既不是 "*共享*" 也不是 "*锁定*"，而是 **不可变的**。这使得运行更简单：工作进程只需使用索引，无需关心 "*锁定*" 或 "*共享*"。当需要切换（加载新索引）时，守护进程只需执行此操作，无需考虑正在运行的查询（以及它们的线程也无需关心“写入者”）。最终，切换只需将活动索引的指针指向新加载的索引，之后所有操作都与 fork 一样：旧查询仍使用旧索引，新查询则指向刚加载的新索引。唯一仍然需要使用独占锁的情况是执行 UPDATE 操作时。

新模型的另一个优势是，我们可以通过重新加载配置文件，动态更改索引的类型。以前，更改索引类型并不总是可以通过修改配置文件并尝试重新加载（通过 HUP 信号）来实现，例如将“普通”索引切换为“分布式”或“分布式”切换为“模板”。现在，当你重新加载新配置时，其中所有旧索引的内容都保留其名称——守护进程会首先解析新配置。如果新配置可以立即使用（这适用于模板和分布式索引）——它会无缝地进行切换。如果新索引是“重型”（即需要预加载到 RAM 中，可能需要几分钟）——切换过程会延迟到它们加载完成。**«延迟»** 意味着调用者会看到“ok”返回，“(所有已切换)”。但实际工作进程仍会将所有新查询发送到旧索引，直到新索引最终加载并激活。
