@@ -51,6 +51,10 @@ type DeltaFIFOOptions struct {
5151 // When true, `Replaced` events will be sent for items passed to a Replace() call.
5252 // When false, `Sync` events will be sent instead.
5353 EmitDeltaTypeReplaced bool
54+
55+ // If set, will be called for objects before enqueueing them. Please
56+ // see the comment on TransformFunc for details.
57+ Transformer TransformFunc
5458}
5559
5660// DeltaFIFO is like FIFO, but differs in two ways. One is that the
@@ -129,8 +133,32 @@ type DeltaFIFO struct {
129133 // emitDeltaTypeReplaced is whether to emit the Replaced or Sync
130134 // DeltaType when Replace() is called (to preserve backwards compat).
131135 emitDeltaTypeReplaced bool
136+
137+ // Called with every object if non-nil.
138+ transformer TransformFunc
132139}
133140
141+ // TransformFunc allows for transforming an object before it will be processed.
142+ // TransformFunc (similarly to ResourceEventHandler functions) should be able
143+ // to correctly handle the tombstone of type cache.DeletedFinalStateUnknown.
144+ //
145+ // New in v1.27: In such cases, the contained object will already have gone
146+ // through the transform object separately (when it was added / updated prior
147+ // to the delete), so the TransformFunc can likely safely ignore such objects
148+ // (i.e., just return the input object).
149+ //
150+ // The most common usage pattern is to clean-up some parts of the object to
151+ // reduce component memory usage if a given component doesn't care about them.
152+ //
153+ // New in v1.27: unless the object is a DeletedFinalStateUnknown, TransformFunc
154+ // sees the object before any other actor, and it is now safe to mutate the
155+ // object in place instead of making a copy.
156+ //
157+ // Note that TransformFunc is called while inserting objects into the
158+ // notification queue and is therefore extremely performance sensitive; please
159+ // do not do anything that will take a long time.
160+ type TransformFunc func (interface {}) (interface {}, error )
161+
134162// DeltaType is the type of a change (addition, deletion, etc)
135163type DeltaType string
136164
@@ -227,6 +255,7 @@ func NewDeltaFIFOWithOptions(opts DeltaFIFOOptions) *DeltaFIFO {
227255 knownObjects : opts .KnownObjects ,
228256
229257 emitDeltaTypeReplaced : opts .EmitDeltaTypeReplaced ,
258+ transformer : opts .Transformer ,
230259 }
231260 f .cond .L = & f .lock
232261 return f
@@ -415,6 +444,21 @@ func (f *DeltaFIFO) queueActionLocked(actionType DeltaType, obj interface{}) err
415444 if err != nil {
416445 return KeyError {obj , err }
417446 }
447+
448+ // Every object comes through this code path once, so this is a good
449+ // place to call the transform func. If obj is a
450+ // DeletedFinalStateUnknown tombstone, then the containted inner object
451+ // will already have gone through the transformer, but we document that
452+ // this can happen. In cases involving Replace(), such an object can
453+ // come through multiple times.
454+ if f .transformer != nil {
455+ var err error
456+ obj , err = f .transformer (obj )
457+ if err != nil {
458+ return err
459+ }
460+ }
461+
418462 oldDeltas := f .items [id ]
419463 newDeltas := append (oldDeltas , Delta {actionType , obj })
420464 newDeltas = dedupDeltas (newDeltas )
0 commit comments