github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/helper/k8smeta/k8s_meta_deferred_deletion_meta_store.go (about) 1 package k8smeta 2 3 import ( 4 "context" 5 "sync" 6 "time" 7 8 "k8s.io/client-go/tools/cache" 9 10 "github.com/alibaba/ilogtail/pkg/logger" 11 ) 12 13 type IndexItem struct { 14 Keys map[string]struct{} // alternative to set, struct{} is zero memory 15 } 16 17 func NewIndexItem() IndexItem { 18 return IndexItem{ 19 Keys: make(map[string]struct{}), 20 } 21 } 22 23 func (i IndexItem) Add(key string) { 24 i.Keys[key] = struct{}{} 25 } 26 27 func (i IndexItem) Remove(key string) { 28 delete(i.Keys, key) 29 } 30 31 type DeferredDeletionMetaStore struct { 32 keyFunc cache.KeyFunc 33 indexRules []IdxFunc 34 35 eventCh chan *K8sMetaEvent 36 stopCh <-chan struct{} 37 38 // cache 39 Items map[string]*ObjectWrapper 40 Index map[string]IndexItem 41 lock sync.RWMutex 42 43 // timer 44 gracePeriod int64 45 registerLock sync.RWMutex 46 sendFuncs map[string]*SendFuncWithStopCh 47 } 48 49 type TimerEvent struct { 50 ConfigName string 51 Interval int 52 } 53 54 type SendFuncWithStopCh struct { 55 SendFunc SendFunc 56 StopCh chan struct{} 57 } 58 59 func NewDeferredDeletionMetaStore(eventCh chan *K8sMetaEvent, stopCh <-chan struct{}, gracePeriod int64, keyFunc cache.KeyFunc, indexRules ...IdxFunc) *DeferredDeletionMetaStore { 60 m := &DeferredDeletionMetaStore{ 61 keyFunc: keyFunc, 62 indexRules: indexRules, 63 64 eventCh: eventCh, 65 stopCh: stopCh, 66 67 Items: make(map[string]*ObjectWrapper), 68 Index: make(map[string]IndexItem), 69 70 gracePeriod: gracePeriod, 71 sendFuncs: make(map[string]*SendFuncWithStopCh), 72 } 73 return m 74 } 75 76 func (m *DeferredDeletionMetaStore) Start() { 77 go m.handleEvent() 78 } 79 80 func (m *DeferredDeletionMetaStore) Get(key []string) map[string][]*ObjectWrapper { 81 m.lock.RLock() 82 defer m.lock.RUnlock() 83 result := make(map[string][]*ObjectWrapper) 84 for _, k := range key { 85 realKeys, ok := m.Index[k] 86 if !ok { 87 continue 88 } 89 for realKey := range realKeys.Keys { 90 if obj, ok := m.Items[realKey]; ok { 91 if obj.Raw != nil { 92 result[k] = append(result[k], obj) 93 } else { 94 logger.Error(context.Background(), "K8S_META_HANDLE_ALARM", "raw object not found", realKey) 95 } 96 } else { 97 logger.Error(context.Background(), "K8S_META_HANDLE_ALARM", "key not found", realKey) 98 } 99 } 100 } 101 return result 102 } 103 104 func (m *DeferredDeletionMetaStore) List() []*ObjectWrapper { 105 m.lock.RLock() 106 defer m.lock.RUnlock() 107 result := make([]*ObjectWrapper, 0) 108 for _, item := range m.Items { 109 result = append(result, item) 110 } 111 return result 112 } 113 114 func (m *DeferredDeletionMetaStore) Filter(filterFunc func(*ObjectWrapper) bool, limit int) []*ObjectWrapper { 115 m.lock.RLock() 116 defer m.lock.RUnlock() 117 result := make([]*ObjectWrapper, 0) 118 for _, item := range m.Items { 119 if filterFunc != nil { 120 if filterFunc(item) { 121 result = append(result, item) 122 } 123 } else { 124 result = append(result, item) 125 } 126 if limit > 0 && len(result) >= limit { 127 break 128 } 129 } 130 return result 131 } 132 133 func (m *DeferredDeletionMetaStore) RegisterSendFunc(key string, f SendFunc, interval int) { 134 sendFuncWithStopCh := &SendFuncWithStopCh{ 135 SendFunc: f, 136 StopCh: make(chan struct{}), 137 } 138 m.registerLock.Lock() 139 m.sendFuncs[key] = sendFuncWithStopCh 140 m.registerLock.Unlock() 141 go func() { 142 defer panicRecover() 143 event := &K8sMetaEvent{ 144 EventType: EventTypeTimer, 145 Object: &ObjectWrapper{ 146 Raw: &TimerEvent{ 147 ConfigName: key, 148 Interval: interval, 149 }, 150 }, 151 } 152 manager := GetMetaManagerInstance() 153 for { 154 if manager.IsReady() { 155 break 156 } 157 time.Sleep(1 * time.Second) 158 } 159 160 m.eventCh <- event 161 ticker := time.NewTicker(time.Duration(interval) * time.Second) 162 for { 163 select { 164 case <-ticker.C: 165 m.eventCh <- event 166 case <-sendFuncWithStopCh.StopCh: 167 return 168 } 169 } 170 }() 171 } 172 173 func (m *DeferredDeletionMetaStore) UnRegisterSendFunc(key string) { 174 m.registerLock.Lock() 175 if stopCh, ok := m.sendFuncs[key]; ok { 176 close(stopCh.StopCh) 177 } 178 delete(m.sendFuncs, key) 179 m.registerLock.Unlock() 180 } 181 182 // realtime events (add, update, delete) and timer events are handled sequentially 183 func (m *DeferredDeletionMetaStore) handleEvent() { 184 defer panicRecover() 185 for { 186 select { 187 case event := <-m.eventCh: 188 switch event.EventType { 189 case EventTypeAdd, EventTypeUpdate: 190 m.handleAddOrUpdateEvent(event) 191 case EventTypeDelete: 192 m.handleDeleteEvent(event) 193 case EventTypeDeferredDelete: 194 m.handleDeferredDeleteEvent(event) 195 case EventTypeTimer: 196 m.handleTimerEvent(event) 197 default: 198 logger.Error(context.Background(), "unknown event type", event.EventType) 199 } 200 case <-m.stopCh: 201 m.registerLock.Lock() 202 for _, f := range m.sendFuncs { 203 close(f.StopCh) 204 } 205 m.registerLock.Unlock() 206 return 207 } 208 } 209 } 210 211 func (m *DeferredDeletionMetaStore) handleAddOrUpdateEvent(event *K8sMetaEvent) { 212 key, err := m.keyFunc(event.Object.Raw) 213 if err != nil { 214 logger.Error(context.Background(), "K8S_META_HANDLE_ALARM", "handle k8s meta with keyFunc error", err) 215 return 216 } 217 idxKeys := m.getIdxKeys(event.Object) 218 m.lock.Lock() 219 // should delete oldIdxKeys in two cases: 220 // 1. update event 221 // 2. add event when the previous object is between deleted and deferred delete 222 if obj, ok := m.Items[key]; ok { 223 var oldIdxKeys []string 224 event.Object.FirstObservedTime = obj.FirstObservedTime 225 oldIdxKeys = m.getIdxKeys(obj) 226 for _, idxKey := range oldIdxKeys { 227 m.Index[idxKey].Remove(key) 228 } 229 } 230 231 m.Items[key] = event.Object 232 for _, idxKey := range idxKeys { 233 if _, ok := m.Index[idxKey]; !ok { 234 m.Index[idxKey] = NewIndexItem() 235 } 236 m.Index[idxKey].Add(key) 237 } 238 m.lock.Unlock() 239 m.registerLock.RLock() 240 for _, f := range m.sendFuncs { 241 f.SendFunc([]*K8sMetaEvent{event}) 242 } 243 m.registerLock.RUnlock() 244 } 245 246 func (m *DeferredDeletionMetaStore) handleDeleteEvent(event *K8sMetaEvent) { 247 key, err := m.keyFunc(event.Object.Raw) 248 if err != nil { 249 logger.Error(context.Background(), "K8S_META_HANDLE_ALARM", "handle k8s meta with keyFunc error", err) 250 return 251 } 252 m.lock.Lock() 253 if obj, ok := m.Items[key]; ok { 254 obj.Deleted = true 255 event.Object.FirstObservedTime = obj.FirstObservedTime 256 } 257 m.lock.Unlock() 258 m.registerLock.RLock() 259 for _, f := range m.sendFuncs { 260 f.SendFunc([]*K8sMetaEvent{event}) 261 } 262 m.registerLock.RUnlock() 263 go func() { 264 // wait and add a deferred delete event 265 time.Sleep(time.Duration(m.gracePeriod) * time.Second) 266 m.eventCh <- &K8sMetaEvent{ 267 EventType: EventTypeDeferredDelete, 268 Object: event.Object, 269 } 270 }() 271 } 272 273 func (m *DeferredDeletionMetaStore) handleDeferredDeleteEvent(event *K8sMetaEvent) { 274 key, err := m.keyFunc(event.Object.Raw) 275 if err != nil { 276 logger.Error(context.Background(), "handleDeferredDeleteEvent keyFunc error", err) 277 return 278 } 279 idxKeys := m.getIdxKeys(event.Object) 280 m.lock.Lock() 281 defer m.lock.Unlock() 282 if obj, ok := m.Items[key]; ok { 283 if obj.Deleted { 284 delete(m.Items, key) 285 for _, idxKey := range idxKeys { 286 if _, ok := m.Index[idxKey]; !ok { 287 continue 288 } 289 m.Index[idxKey].Remove(key) 290 if len(m.Index[idxKey].Keys) == 0 { 291 delete(m.Index, idxKey) 292 } 293 } 294 } 295 // if deleted is false, there is a new add event between delete event and deferred delete event 296 } 297 } 298 299 func (m *DeferredDeletionMetaStore) handleTimerEvent(event *K8sMetaEvent) { 300 timerEvent := event.Object.Raw.(*TimerEvent) 301 m.registerLock.RLock() 302 defer m.registerLock.RUnlock() 303 if f, ok := m.sendFuncs[timerEvent.ConfigName]; ok { 304 allItems := make([]*K8sMetaEvent, 0) 305 m.lock.RLock() 306 for _, obj := range m.Items { 307 if !obj.Deleted { 308 obj.LastObservedTime = time.Now().Unix() 309 allItems = append(allItems, &K8sMetaEvent{ 310 EventType: EventTypeUpdate, 311 Object: obj, 312 }) 313 } 314 } 315 m.lock.RUnlock() 316 f.SendFunc(allItems) 317 } 318 } 319 320 func (m *DeferredDeletionMetaStore) getIdxKeys(obj *ObjectWrapper) []string { 321 result := make([]string, 0) 322 for _, rule := range m.indexRules { 323 idxKeys, err := rule(obj.Raw) 324 if err != nil { 325 logger.Error(context.Background(), "K8S_META_HANDLE_ALARM", "handle k8s meta with idx rules error", err) 326 return nil 327 } 328 result = append(result, idxKeys...) 329 } 330 return result 331 }