Commit 7cab1878 authored by Jacob Vosmaer's avatar Jacob Vosmaer

Merge branch '225619-cache-references-v2' into 'master'

Cache references in file

See merge request gitlab-org/gitlab-workhorse!544
parents 9fb459d8 67a20e2c
---
title: Cache references in file
merge_request: 544
author:
type: performance
...@@ -17,7 +17,6 @@ type Ranges struct { ...@@ -17,7 +17,6 @@ type Ranges struct {
References *References References *References
Hovers *Hovers Hovers *Hovers
Cache *cache Cache *cache
ProcessReferences bool
} }
type RawRange struct { type RawRange struct {
...@@ -57,6 +56,11 @@ func NewRanges(config Config) (*Ranges, error) { ...@@ -57,6 +56,11 @@ func NewRanges(config Config) (*Ranges, error) {
return nil, err return nil, err
} }
references, err := NewReferences(config)
if err != nil {
return nil, err
}
cache, err := newCache(config.TempPath, "ranges", Range{}) cache, err := newCache(config.TempPath, "ranges", Range{})
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -64,7 +68,7 @@ func NewRanges(config Config) (*Ranges, error) { ...@@ -64,7 +68,7 @@ func NewRanges(config Config) (*Ranges, error) {
return &Ranges{ return &Ranges{
DefRefs: make(map[Id]Item), DefRefs: make(map[Id]Item),
References: NewReferences(config), References: references,
Hovers: hovers, Hovers: hovers,
Cache: cache, Cache: cache,
}, nil }, nil
...@@ -128,6 +132,7 @@ func (r *Ranges) Serialize(f io.Writer, rangeIds []Id, docs map[Id]string) error ...@@ -128,6 +132,7 @@ func (r *Ranges) Serialize(f io.Writer, rangeIds []Id, docs map[Id]string) error
func (r *Ranges) Close() error { func (r *Ranges) Close() error {
return combineErrors( return combineErrors(
r.Cache.Close(), r.Cache.Close(),
r.References.Close(),
r.Hovers.Close(), r.Hovers.Close(),
) )
} }
...@@ -192,7 +197,9 @@ func (r *Ranges) addItem(line []byte) error { ...@@ -192,7 +197,9 @@ func (r *Ranges) addItem(line []byte) error {
} }
} }
r.References.Store(rawItem.RefId, references) if err := r.References.Store(rawItem.RefId, references); err != nil {
return err
}
return nil return nil
} }
......
...@@ -4,8 +4,15 @@ import ( ...@@ -4,8 +4,15 @@ import (
"strconv" "strconv"
) )
type ReferencesOffset struct {
Id Id
Len int32
}
type References struct { type References struct {
Items map[Id][]Item Items *cache
Offsets *cache
CurrentOffsetId Id
ProcessReferences bool ProcessReferences bool
} }
...@@ -13,17 +20,50 @@ type SerializedReference struct { ...@@ -13,17 +20,50 @@ type SerializedReference struct {
Path string `json:"path"` Path string `json:"path"`
} }
func NewReferences(config Config) *References { func NewReferences(config Config) (*References, error) {
tempPath := config.TempPath
items, err := newCache(tempPath, "references", Item{})
if err != nil {
return nil, err
}
offsets, err := newCache(tempPath, "references-offsets", ReferencesOffset{})
if err != nil {
return nil, err
}
return &References{ return &References{
Items: make(map[Id][]Item), Items: items,
Offsets: offsets,
CurrentOffsetId: 0,
ProcessReferences: config.ProcessReferences, ProcessReferences: config.ProcessReferences,
} }, nil
} }
func (r *References) Store(refId Id, references []Item) { // Store is responsible for keeping track of references that will be used when
if r.ProcessReferences { // serializing in `For`.
r.Items[refId] = references //
// The references are stored in a file to cache them. It is like
// `map[Id][]Item` (where `Id` is `refId`) but relies on caching the array and
// its offset in files for storage to reduce RAM usage. The items can be
// fetched by calling `getItems`.
func (r *References) Store(refId Id, references []Item) error {
size := len(references)
if !r.ProcessReferences || size == 0 {
return nil
}
err := r.Items.SetEntry(r.CurrentOffsetId, references)
if err != nil {
return err
} }
r.Offsets.SetEntry(refId, ReferencesOffset{Id: r.CurrentOffsetId, Len: int32(size)})
r.CurrentOffsetId += Id(size)
return nil
} }
func (r *References) For(docs map[Id]string, refId Id) []SerializedReference { func (r *References) For(docs map[Id]string, refId Id) []SerializedReference {
...@@ -31,8 +71,8 @@ func (r *References) For(docs map[Id]string, refId Id) []SerializedReference { ...@@ -31,8 +71,8 @@ func (r *References) For(docs map[Id]string, refId Id) []SerializedReference {
return nil return nil
} }
references, ok := r.Items[refId] references := r.getItems(refId)
if !ok { if references == nil {
return nil return nil
} }
...@@ -48,3 +88,24 @@ func (r *References) For(docs map[Id]string, refId Id) []SerializedReference { ...@@ -48,3 +88,24 @@ func (r *References) For(docs map[Id]string, refId Id) []SerializedReference {
return serializedReferences return serializedReferences
} }
func (r *References) Close() error {
return combineErrors(
r.Items.Close(),
r.Offsets.Close(),
)
}
func (r *References) getItems(refId Id) []Item {
var offset ReferencesOffset
if err := r.Offsets.Entry(refId, &offset); err != nil || offset.Len == 0 {
return nil
}
items := make([]Item, offset.Len)
if err := r.Items.Entry(offset.Id, &items); err != nil {
return nil
}
return items
}
...@@ -12,13 +12,33 @@ func TestReferencesStore(t *testing.T) { ...@@ -12,13 +12,33 @@ func TestReferencesStore(t *testing.T) {
refId = 3 refId = 3
) )
r := NewReferences(Config{ProcessReferences: true}) r, err := NewReferences(Config{ProcessReferences: true})
require.NoError(t, err)
r.Store(refId, []Item{{Line: 2, DocId: docId}, {Line: 3, DocId: docId}}) err = r.Store(refId, []Item{{Line: 2, DocId: docId}, {Line: 3, DocId: docId}})
require.NoError(t, err)
docs := map[Id]string{docId: "doc.go"} docs := map[Id]string{docId: "doc.go"}
serializedReferences := r.For(docs, refId) serializedReferences := r.For(docs, refId)
require.Contains(t, serializedReferences, SerializedReference{Path: "doc.go#L2"}) require.Contains(t, serializedReferences, SerializedReference{Path: "doc.go#L2"})
require.Contains(t, serializedReferences, SerializedReference{Path: "doc.go#L3"}) require.Contains(t, serializedReferences, SerializedReference{Path: "doc.go#L3"})
require.NoError(t, r.Close())
}
func TestReferencesStoreEmpty(t *testing.T) {
const refId = 3
r, err := NewReferences(Config{ProcessReferences: true})
require.NoError(t, err)
err = r.Store(refId, []Item{})
require.NoError(t, err)
docs := map[Id]string{1: "doc.go"}
serializedReferences := r.For(docs, refId)
require.Nil(t, serializedReferences)
require.NoError(t, r.Close())
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment