Refactor Repository's ref reading/writing for aggressive caching
We kept reading the packed-refs file on every request for the refs,
as we never updated our cached last modification time. We also did
not remember the peeled ref information if it was available in the
packed-refs file, making client applications potentially spend CPU
time to parse the tag.
By storing all ref data as a Ref object we can return all known
packed ref entries, along with their peeled object (if available)
without needing to re-read the file or create a new Ref object for
the read request. This reduces the costs associated with reading
all available refs.
The packed-refs file is cached by remembering the combination
of both modification time and file size, to try and avoid racy
update operations. The caching is not perfect as we cannot detect
all updates if they happen too quickly, but it is good enough for
most uses against packed-refs as the file is not usually updated
more than once per minute.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>