github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/vector/hnsw/vector_cache_prefiller.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package hnsw 13 14 import ( 15 "context" 16 "time" 17 18 "github.com/sirupsen/logrus" 19 "github.com/weaviate/weaviate/adapters/repos/db/vector/cache" 20 ) 21 22 type vectorCachePrefiller[T any] struct { 23 cache cache.Cache[T] 24 index *hnsw 25 logger logrus.FieldLogger 26 } 27 28 func newVectorCachePrefiller[T any](cache cache.Cache[T], index *hnsw, 29 logger logrus.FieldLogger, 30 ) *vectorCachePrefiller[T] { 31 return &vectorCachePrefiller[T]{ 32 cache: cache, 33 index: index, 34 logger: logger, 35 } 36 } 37 38 func (pf *vectorCachePrefiller[T]) Prefill(ctx context.Context, limit int) error { 39 before := time.Now() 40 for level := pf.maxLevel(); level >= 0; level-- { 41 ok, err := pf.prefillLevel(ctx, level, limit) 42 if err != nil { 43 return err 44 } 45 46 if !ok { 47 break 48 } 49 } 50 51 pf.logTotal(int(pf.cache.Len()), limit, before) 52 return nil 53 } 54 55 // returns false if the max has been reached, true otherwise 56 func (pf *vectorCachePrefiller[T]) prefillLevel(ctx context.Context, 57 level, limit int, 58 ) (bool, error) { 59 // TODO: this makes zero sense, just copy the lists, don't actually block 60 // !!!! 61 62 before := time.Now() 63 layerCount := 0 64 65 pf.index.Lock() 66 nodesLen := len(pf.index.nodes) 67 pf.index.Unlock() 68 69 for i := 0; i < nodesLen; i++ { 70 if int(pf.cache.Len()) >= limit { 71 break 72 } 73 74 if err := ctx.Err(); err != nil { 75 return false, err 76 } 77 78 pf.index.shardedNodeLocks.RLock(uint64(i)) 79 node := pf.index.nodes[i] 80 pf.index.shardedNodeLocks.RUnlock(uint64(i)) 81 82 if node == nil { 83 continue 84 } 85 86 if levelOfNode(node) != level { 87 continue 88 } 89 90 // we are not really interested in the result, we just want to populate the 91 // cache 92 pf.index.Lock() 93 pf.cache.Get(ctx, uint64(i)) 94 layerCount++ 95 pf.index.Unlock() 96 } 97 98 pf.logLevel(level, layerCount, before) 99 return true, nil 100 } 101 102 func (pf *vectorCachePrefiller[T]) logLevel(level, count int, before time.Time) { 103 pf.logger.WithFields(logrus.Fields{ 104 "action": "hnsw_vector_cache_prefill_level", 105 "hnsw_level": level, 106 "count": count, 107 "took": time.Since(before), 108 "index_id": pf.index.id, 109 }).Debug("prefilled level in vector cache") 110 } 111 112 func (pf *vectorCachePrefiller[T]) logTotal(count, limit int, before time.Time) { 113 pf.logger.WithFields(logrus.Fields{ 114 "action": "hnsw_vector_cache_prefill", 115 "limit": limit, 116 "count": count, 117 "took": time.Since(before), 118 "index_id": pf.index.id, 119 }).Info("prefilled vector cache") 120 } 121 122 func levelOfNode(node *vertex) int { 123 node.Lock() 124 defer node.Unlock() 125 126 return node.level 127 } 128 129 func (pf *vectorCachePrefiller[T]) maxLevel() int { 130 pf.index.Lock() 131 defer pf.index.Unlock() 132 133 return pf.index.currentMaximumLayer 134 }