// decodeList decodes a list of values into a list of objects, with resource version set to corresponding rev. // On success, ListPtr would be set to the list of objects. func decodeList(elems []*elemForDecode, filter storage.Filter, ListPtr interface{}, codec runtime.Codec, versioner storage.Versioner) error { v, err := conversion.EnforcePtr(ListPtr) if err != nil || v.Kind() != reflect.Slice { panic("need ptr to slice") } for _, elem := range elems { obj, _, err := codec.Decode(elem.data, nil, reflect.New(v.Type().Elem()).Interface().(runtime.Object)) if err != nil { return err } // being unable to set the version does not prevent the object from being extracted versioner.UpdateObject(obj, elem.rev) if filter.Filter(obj) { v.Set(reflect.Append(v, reflect.ValueOf(obj).Elem())) } } return nil }
// decodeNodeList walks the tree of each node in the list and decodes into the specified object func (h *etcdHelper) decodeNodeList(nodes []*etcd.Node, filter storage.Filter, slicePtr interface{}) error { trace := util.NewTrace("decodeNodeList " + getTypeName(slicePtr)) defer trace.LogIfLong(400 * time.Millisecond) v, err := conversion.EnforcePtr(slicePtr) if err != nil || v.Kind() != reflect.Slice { // This should not happen at runtime. panic("need ptr to slice") } for _, node := range nodes { if node.Dir { trace.Step("Decoding dir " + node.Key + " START") if err := h.decodeNodeList(node.Nodes, filter, slicePtr); err != nil { return err } trace.Step("Decoding dir " + node.Key + " END") continue } if obj, found := h.getFromCache(node.ModifiedIndex, filter); found { // obj != nil iff it matches the filter function. if obj != nil { v.Set(reflect.Append(v, reflect.ValueOf(obj).Elem())) } } else { obj, _, err := h.codec.Decode([]byte(node.Value), nil, reflect.New(v.Type().Elem()).Interface().(runtime.Object)) if err != nil { return err } // being unable to set the version does not prevent the object from being extracted _ = h.versioner.UpdateObject(obj, node.ModifiedIndex) if filter.Filter(obj) { v.Set(reflect.Append(v, reflect.ValueOf(obj).Elem())) } if node.ModifiedIndex != 0 { h.addToCache(node.ModifiedIndex, obj) } } } trace.Step(fmt.Sprintf("Decoded %v nodes", len(nodes))) return nil }
func (h *etcdHelper) getFromCache(index uint64, filter storage.Filter) (runtime.Object, bool) { startTime := time.Now() defer func() { metrics.ObserveGetCache(startTime) }() obj, found := h.cache.Get(index) if found { if !filter.Filter(obj.(runtime.Object)) { return nil, true } // We should not return the object itself to avoid polluting the cache if someone // modifies returned values. objCopy, err := h.copier.Copy(obj.(runtime.Object)) if err != nil { glog.Errorf("Error during DeepCopy of cached object: %q", err) // We can't return a copy, thus we report the object as not found. return nil, false } metrics.ObserveCacheHit() return objCopy.(runtime.Object), true } metrics.ObserveCacheMiss() return nil, false }