code: func (r *Cache) Get(ns, key uint64, setFunc func() (size int, value Value)) *Handle {
  	r.mu.RLock()
  	defer r.mu.RUnlock()
  	if r.closed {
  		return nil
  	}
  
  	hash := murmur32(ns, key, 0xf00)
  	for {
  		h, b := r.getBucket(hash)
  		done, _, n := b.get(r, h, hash, ns, key, setFunc == nil)
  		if done {
  			if n != nil {
  				n.mu.Lock()
  				if n.value == nil {
  					if setFunc == nil {
  						n.mu.Unlock()
  						n.unref()
  						return nil
  					}
  
  					n.size, n.value = setFunc()
  					if n.value == nil {
  						n.size = 0
  						n.mu.Unlock()
  						n.unref()
  						return nil
  					}
  					atomic.AddInt32(&r.size, int32(n.size))
  				}
  				n.mu.Unlock()
  				if r.cacher != nil {
  					r.cacher.Promote(n)
  				}
  				return &Handle{unsafe.Pointer(n)}
  			}
  
  			break
  		}
  	}
  	return nil
  }
docs: // Get gets 'cache node' with the given namespace and key.
  // If cache node is not found and setFunc is not nil, Get will atomically creates
  // the 'cache node' by calling setFunc. Otherwise Get will returns nil.
  //
  // The returned 'cache handle' should be released after use by calling Release
  // method.