CHI-Read Transaction
读请求可以分为两类:Allocating Read、Non-allocating Read
Allocating Read
ReadClean
目的:获取一个 干净的、只读的 数据副本。
期望状态:Shared。
对系统影响:最轻微。它明确告诉 Home Node:“我不想要脏数据”。如果数据在某个节点的缓存中是脏的,HN 会先将其写回内存,然后从内存提供干净的副本给请求者。它不会主动去无效化其他节点的 Shared 副本。
使用场景:获取绝对不会被修改的只读数据,如代码、常量。旨在减少对脏数据持有者的干扰。
ReadNotSharedDirty
目的:获取数据,但 不希望数据来自一个处于 Shared-dirty 状态的缓存。
期望状态:Shared。
对系统影响:比
ReadClean
稍强。它允许从 Unique-dirty 的缓存获取数据,但不允许从 Shared-dirty 的缓存获取。如果数据是 Shared-dirty,HN 会先将其写回内存使其变干净。使用场景:一种平衡的策略,避免从共享的脏数据源获取数据,但仍允许从独占的脏数据源获取以降低延迟。
ReadShared
目的:获取一个 可读的 数据副本。这是最通用、最常见的共享读请求。
期望状态:Shared。
对系统影响:HN 会从最快的数据源(可能是内存,也可能是持有脏数据或干净数据的缓存)提供数据。它会保留其他节点的 Shared 副本,但会无效化 Unique 副本(将其降级为 Shared)。
使用场景:绝大多数普通的读操作,期望与其他请求者共享数据。
ReadUnique
目的:获取一个 可写的 数据副本。请求者计划未来修改这个数据。
期望状态:Unique。
对系统影响:强烈。HN 必须确保请求者获得独占权。它会无效化所有其他缓存中的副本。如果数据是脏的,它会从那个缓存获取数据并转发给请求者。
使用场景:在写入数据之前使用,为写入做准备。相当于“为我准备写权限”。
ReadPreferUnique
目的:获取数据,倾向于获得独占权,但如果不行,共享状态也可以接受。
期望状态:Unique > Shared。
对系统影响:一个灵活的优化选项。HN 会根据实际情况决定:如果无效化其他副本的代价很小(比如只有一个其他共享者),就授予 Unique 状态;如果代价很大(有很多共享者),就只授予 Shared 状态。
使用场景:不确定是否会修改数据,但如果能轻松获得写权限更好。用于优化潜在的写操作。
MakeReadUnique
目的:将当前已缓存的、状态为 Shared 的数据升级为 Unique。这是一个升级操作,而非纯粹的获取操作。
期望状态:Unique。
对系统影响:与
ReadUnique
类似,HN 会无效化所有其他缓存中的副本。关键区别在于,请求者自己已经有一份 Shared 副本。因此,HN 可能不需要再发送数据,只需发送一个完成响应,告诉请求者升级已完成。使用场景:请求者原本以只读方式缓存了数据,但现在决定要修改它。这是一个非常高效的升级路径。
简单来说,它是在说:“请把数据给我,并且确保我现在是唯一拥有写入权限的人。”

Unallocating Read
不触发侦听 的read,这意味着 Home Node 在处理这些请求时,不会向其他可能的缓存持有者发送 Snoop 请求来维护一致性。它们用于特定的优化场景,牺牲严格的一致性来换取更低的延迟和更少的带宽消耗。
优势:延迟极低,因为没有等待 Snoop 响应和数据的开销。
代价:可能读取到旧数据,如果该数据的最新副本正脏在其他节点的缓存中。
ReadNoSnp
目的:直接从内存(或 HN 的集成缓存)读取数据,完全绕过缓存一致性检查。
数据源:内存。即使 HN 知道数据在某个缓存中是脏的,它也会忽略脏数据,直接从内存读取并返回。
对系统影响:
不发送 Snoop。
不改变任何缓存的状态。
缓存分配:请求者可以将读取的数据缓存起来(状态通常为 Shared)。
使用场景:
I/O 设备访问:RN-I(如网卡)读取内存,它不关心缓存,只需要一个数据副本。
非临时数据:读取很快就会被覆盖的数据,不希望污染缓存。
软件管理的一致性:在软件已经确保内存数据是最新的之后使用(例如,在 DMA 传输完成后)。
ReadOnce
目的:一次性读取数据,明确表示不会重复使用。
数据源:HN 会从最快的可用源提供数据——可能是内存,也可能是持有干净数据的缓存。它不会从脏的缓存中取数据。
对系统影响:
不发送 Snoop。
不改变其他缓存的状态。
缓存分配:请求者强烈建议不缓存此数据。即使缓存,也会被标记为很快被驱逐。
使用场景:
流式数据:读取一个数据流中的下一个元素,每个元素只使用一次。
随机扫描:大规模数据集中不重复的随机访问。
ReadOnceCleanInvalid
目的:在
ReadOnce
的基础上更进一步,不仅自己不缓存,还要保证数据源是干净的,并可能无效化数据源。数据源:干净的缓存或内存。如果数据在一个缓存中是干净的,HN 可能会从该缓存获取数据。如果数据是脏的,HN 会从内存提供干净副本。
对系统影响:
可能会使提供数据的干净缓存源无效化。这是一种轻度的一致性操作,但目标不是获取最新数据,而是“清理”路径。
缓存分配:请求者不缓存此数据。
使用场景:
在保证数据来自干净源的同时进行一次性读取。常用于在共享缓存中读取,并希望减少未来冲突的场景。
ReadOnceMakeInvalid
目的:这是最“激进”的一次性读取。它要求获取数据,并确保该数据在返回后,在整个系统中不再有缓存副本。
数据源:最快的可用源,包括脏缓存。HN 会像处理正常读请求一样获取数据。
对系统影响:
会发送 Snoop! 这是本组中一个关键的例外。HN 会向所有缓存持有者发送
SnpUnique
或类似的 Snoop,以无效化它们的副本。确保在请求者收到数据后,它是系统中唯一的缓存副本(但请求者自己还不会缓存它)。
缓存分配:请求者不缓存此数据。
使用场景:
机密性/安全性:读取一个安全密钥,并确保在使用后系统中没有残留的缓存副本。
内存自测试:测试内存后,不希望有任何缓存数据干扰后续测试。
极其临时的数据:确保这次读取不影响任何其他缓存的工作集。