code: func (ss *Rate) Touch(key string, nowTs time.Time) {
  	now := nowTs.UnixNano()
  
  	var bucket *bucket
  	if bucketno, found := ss.keytobucketno[key]; found {
  		bucket = &ss.buckets[bucketno]
  	} else {
  		bucketno = uint32(ss.sh.h[0])
  
  		bucket = &ss.buckets[bucketno]
  		delete(ss.keytobucketno, bucket.key)
  		ss.keytobucketno[key] = bucketno
  
  		bucket.key, bucket.errLastTs, bucket.errRate =
  			key, bucket.lastTs, bucket.rate
  	}
  
  	if bucket.lastTs != 0 {
  		bucket.rate = ss.count(bucket.rate, bucket.lastTs, now)
  	}
  	bucket.lastTs = now
  
  	// Even lastTs change may change ordering.
  	heap.Fix(&ss.sh, int(bucket.idx))
  }
docs: // Mark an event happening, using given timestamp.
  //
  // The implementation assumes time is monotonic, the behaviour is undefined in
  // the case of time going back. This operation has logarithmic complexity.