forked from Botanical/BotanJS
108 lines
1.8 KiB
Go
108 lines
1.8 KiB
Go
package compilecache
|
|
|
|
import (
|
|
"context"
|
|
)
|
|
|
|
func New(compiler Compiler, opt Options) *Cache {
|
|
if opt.Workers <= 0 {
|
|
opt.Workers = 1
|
|
}
|
|
if opt.QueueSize <= 0 {
|
|
opt.QueueSize = 128
|
|
}
|
|
|
|
c := &Cache{
|
|
compiler: compiler,
|
|
disableCache: opt.DisableCache,
|
|
states: make(map[string]State),
|
|
results: make(map[string][]byte),
|
|
errors: make(map[string]error),
|
|
jobs: make(chan Job, opt.QueueSize),
|
|
}
|
|
|
|
if !opt.DisableCache {
|
|
for i := 0; i < opt.Workers; i++ {
|
|
go c.worker()
|
|
}
|
|
}
|
|
|
|
return c
|
|
}
|
|
|
|
func (c *Cache) Get(hash string) (State, []byte, error) {
|
|
if c.disableCache {
|
|
return Missing, nil, nil
|
|
}
|
|
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
state, ok := c.states[hash]
|
|
if !ok {
|
|
return Missing, nil, nil
|
|
}
|
|
|
|
switch state {
|
|
case Ready:
|
|
return Ready, c.results[hash], nil
|
|
case Failed:
|
|
return Failed, nil, c.errors[hash]
|
|
default:
|
|
return state, nil, nil
|
|
}
|
|
}
|
|
|
|
func (c *Cache) Enqueue(job Job) State {
|
|
if c.disableCache {
|
|
// Pretend every request is new.
|
|
// Caller will see Pending forever unless something else reads result,
|
|
// so this only works if your caller does not rely on cache state.
|
|
go c.runUncached(job)
|
|
return Pending
|
|
}
|
|
|
|
c.mu.Lock()
|
|
|
|
state, ok := c.states[job.Hash]
|
|
if ok {
|
|
c.mu.Unlock()
|
|
return state
|
|
}
|
|
|
|
c.states[job.Hash] = Pending
|
|
c.mu.Unlock()
|
|
|
|
c.jobs <- job
|
|
|
|
return Pending
|
|
}
|
|
|
|
func (c *Cache) runUncached(job Job) {
|
|
_, _ = c.compiler.Compile(context.Background(), job)
|
|
}
|
|
|
|
func (c *Cache) worker() {
|
|
for job := range c.jobs {
|
|
c.run(job)
|
|
}
|
|
}
|
|
|
|
func (c *Cache) run(job Job) {
|
|
result, err := c.compiler.Compile(context.Background(), job)
|
|
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
if err != nil {
|
|
c.states[job.Hash] = Failed
|
|
c.errors[job.Hash] = err
|
|
delete(c.results, job.Hash)
|
|
return
|
|
}
|
|
|
|
c.states[job.Hash] = Ready
|
|
c.results[job.Hash] = result
|
|
delete(c.errors, job.Hash)
|
|
}
|