2
0

unique_cache.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package storage
  2. import "strings"
  3. // UNIQUE caches use the constraint encoder, not the coarser SELECT candidate
  4. // encoder. Owners are actual durable keys, preserving NULL and legacy-key rules.
  5. // Validation and publication hold the table's exclusive gate. cacheMu protects
  6. // cache membership and removals from shared-gate point deletes.
  7. type uniqueIndexCache struct {
  8. table string
  9. values map[string]map[string]bool
  10. keys map[string]string
  11. }
  12. type uniqueCacheChange struct {
  13. name string
  14. cache *uniqueIndexCache
  15. values map[string]*string // nil removes a key or represents a NULL index value
  16. }
  17. type uniqueCachePlan []uniqueCacheChange
  18. func (m *TableManager) prepareUniqueRows(table string, entries map[string]*overlayEntry) (uniqueCachePlan, error) {
  19. indexes, err := m.uniqueIndexes(table)
  20. if err != nil {
  21. return nil, err
  22. }
  23. if len(indexes) == 0 {
  24. return nil, nil
  25. }
  26. caches, err := m.ensureUniqueCaches(table, indexes)
  27. if err != nil {
  28. return nil, err
  29. }
  30. plan := make(uniqueCachePlan, 0, len(indexes))
  31. for _, idx := range indexes {
  32. cache := caches[idx.Name]
  33. change := uniqueCacheChange{name: strings.ToLower(idx.Name), cache: cache, values: make(map[string]*string, len(entries))}
  34. seen := make(map[string]bool)
  35. for key, entry := range entries {
  36. change.values[key] = nil
  37. if entry.absent {
  38. continue
  39. }
  40. value, isNull, err := m.encodeUniqueValue(entry.row, idx.Columns)
  41. if err != nil {
  42. return nil, err
  43. }
  44. if isNull {
  45. continue
  46. }
  47. if seen[value] {
  48. return nil, &UniqueViolationError{Constraint: idx.Name}
  49. }
  50. seen[value] = true
  51. for owner := range cache.values[value] {
  52. if _, replaced := entries[owner]; !replaced {
  53. return nil, &UniqueViolationError{Constraint: idx.Name}
  54. }
  55. }
  56. change.values[key] = &value
  57. }
  58. plan = append(plan, change)
  59. }
  60. return plan, nil
  61. }
  62. func (m *TableManager) ensureUniqueCaches(table string, indexes []*Index) (map[string]*uniqueIndexCache, error) {
  63. caches := make(map[string]*uniqueIndexCache, len(indexes))
  64. var missing []*Index
  65. m.cacheMu.RLock()
  66. for _, idx := range indexes {
  67. if cache := m.uniqueCache[strings.ToLower(idx.Name)]; cache != nil && cacheableColumnIndex(idx) {
  68. caches[idx.Name] = cache
  69. } else {
  70. missing = append(missing, idx)
  71. }
  72. }
  73. m.cacheMu.RUnlock()
  74. if len(missing) == 0 {
  75. return caches, nil
  76. }
  77. for _, idx := range missing {
  78. caches[idx.Name] = &uniqueIndexCache{table: strings.ToLower(table), values: make(map[string]map[string]bool), keys: make(map[string]string)}
  79. }
  80. err := m.pool.WithClient(func(client *KVClient) (retErr error) {
  81. cursor, err := client.ScanWithLimit([]byte(m.dataPrefix(table)), scanPageSize)
  82. if err != nil {
  83. return err
  84. }
  85. defer func() {
  86. if err := cursor.Close(); retErr == nil {
  87. retErr = err
  88. }
  89. }()
  90. for {
  91. entries, done, err := cursor.Next()
  92. if err != nil {
  93. return err
  94. }
  95. for _, entry := range entries {
  96. row, err := decodeRow(entry.Value)
  97. if err != nil {
  98. return err
  99. }
  100. for _, idx := range missing {
  101. value, isNull, err := m.encodeUniqueValue(row, idx.Columns)
  102. if err != nil {
  103. return err
  104. }
  105. if !isNull {
  106. caches[idx.Name].add(string(entry.Key), value)
  107. }
  108. }
  109. }
  110. if done {
  111. return nil
  112. }
  113. }
  114. })
  115. if err != nil {
  116. return nil, err
  117. }
  118. m.cacheMu.Lock()
  119. for _, idx := range missing {
  120. if cacheableColumnIndex(idx) {
  121. m.uniqueCache[strings.ToLower(idx.Name)] = caches[idx.Name]
  122. }
  123. }
  124. m.cacheMu.Unlock()
  125. return caches, nil
  126. }
  127. // Expression evaluators have no determinism contract. Rebuild these constraints
  128. // for each validation rather than freezing time/random/function-dependent values.
  129. func cacheableColumnIndex(index *Index) bool {
  130. for _, column := range index.Columns {
  131. if column.Expression != "" {
  132. return false
  133. }
  134. }
  135. return true
  136. }
  137. func (c *uniqueIndexCache) remove(key string) {
  138. value, ok := c.keys[key]
  139. if !ok {
  140. return
  141. }
  142. delete(c.keys, key)
  143. delete(c.values[value], key)
  144. if len(c.values[value]) == 0 {
  145. delete(c.values, value)
  146. }
  147. }
  148. func (c *uniqueIndexCache) add(key, value string) {
  149. if c.values[value] == nil {
  150. c.values[value] = make(map[string]bool)
  151. }
  152. c.values[value][key] = true
  153. c.keys[key] = value
  154. }
  155. // Apply only after durable success. accepted is used by the storage bulk API,
  156. // which can commit several batches; SQL statements use one atomic transaction.
  157. func (m *TableManager) applyUniquePlan(plan uniqueCachePlan, accepted map[string]bool) {
  158. if len(plan) == 0 {
  159. return
  160. }
  161. m.cacheMu.Lock()
  162. defer m.cacheMu.Unlock()
  163. for _, change := range plan {
  164. if m.uniqueCache[change.name] != change.cache {
  165. continue
  166. }
  167. for key := range change.values {
  168. if accepted == nil || accepted[key] {
  169. change.cache.remove(key)
  170. }
  171. }
  172. for key, value := range change.values {
  173. if value != nil && (accepted == nil || accepted[key]) {
  174. change.cache.add(key, *value)
  175. }
  176. }
  177. }
  178. }
  179. // A transport failure may hide a durable write. Drop derived state and make
  180. // earlier predicate/scan snapshots retry rather than trusting an unknown outcome.
  181. // Callers retain their normal table publication gate.
  182. func (m *TableManager) invalidateWriteFailure(table string) {
  183. m.InvalidateCache(table)
  184. m.bumpIndexPredicateWildcard(table)
  185. m.bumpGeneration(table)
  186. }
  187. func (m *TableManager) removeUniqueKey(table, key string) {
  188. m.cacheMu.Lock()
  189. defer m.cacheMu.Unlock()
  190. for _, cache := range m.uniqueCache {
  191. if cache.table == strings.ToLower(table) {
  192. cache.remove(key)
  193. }
  194. }
  195. }