Skip to content

Commit 235c24e

Browse files
authored
feat: add timeout handling for cache database operations (#9307)
1 parent 04ad0c4 commit 235c24e

File tree

4 files changed

+64
-11
lines changed

4 files changed

+64
-11
lines changed

docs/docs/references/troubleshooting.md

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,57 @@ $ trivy image --download-java-db-only
125125
$ trivy image [YOUR_JAVA_IMAGE]
126126
```
127127

128-
### Running in parallel takes same time as series run
129-
When running trivy on multiple images simultaneously, it will take same time as running trivy in series.
130-
This is because of a limitation of boltdb.
131-
> Bolt obtains a file lock on the data file so multiple processes cannot open the same database at the same time. Opening an already open Bolt database will cause it to hang until the other process closes it.
128+
### Database and cache lock errors
132129

133-
Reference : [boltdb: Opening a database][boltdb].
130+
!!! error
131+
```
132+
cache may be in use by another process
133+
```
134+
135+
!!! error
136+
```
137+
vulnerability database may be in use by another process
138+
```
139+
140+
By default, Trivy uses BoltDB for its vulnerability database and cache storage. BoltDB creates file locks to prevent data corruption, which means only one process can access the same database file at a time.
141+
142+
As stated in the BoltDB documentation:
143+
144+
> Please note that Bolt obtains a file lock on the data file so multiple processes cannot open the same database at the same time. Opening an already open Bolt database will cause it to hang until the other process closes it.
145+
146+
Reference: [BoltDB README](https://github.com/boltdb/bolt#opening-a-database)
147+
148+
These errors occur when:
149+
150+
- Multiple Trivy processes try to use the same cache directory simultaneously
151+
- A previous Trivy process did not shut down cleanly
152+
- Trivy server is running and holding locks on the database and cache
153+
154+
#### Important Note
155+
156+
Running multiple Trivy processes on the same machine is **not recommended**. Using the same cache directory for multiple processes does not improve performance and can cause unexpected errors due to BoltDB's locking mechanism.
157+
158+
#### Solutions
159+
160+
**Solution 1: Terminate conflicting processes** (Recommended)
161+
162+
Check for running Trivy processes and terminate them:
163+
164+
```bash
165+
$ ps aux | grep trivy
166+
$ kill [process_id]
167+
```
168+
169+
**Solution 2: Use different cache directories** (If multiple processes are absolutely necessary)
170+
171+
If you must run multiple Trivy processes on the same machine, specify different cache directories for each process:
172+
173+
```bash
174+
$ trivy image --cache-dir /tmp/trivy-cache-1 debian:11 &
175+
$ trivy image --cache-dir /tmp/trivy-cache-2 debian:12 &
176+
```
134177

135-
[boltdb]: https://github.com/boltdb/bolt#opening-a-database
178+
Note that each cache directory will download its own copy of the vulnerability database and other scan assets, which will increase network traffic and storage usage.
136179

137180
### Multiple Trivy servers
138181

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ require (
2424
github.com/aquasecurity/testdocker v0.0.0-20250616060700-ba6845ac6d17
2525
github.com/aquasecurity/tml v0.6.1
2626
github.com/aquasecurity/trivy-checks v1.11.3-0.20250604022615-9a7efa7c9169
27-
github.com/aquasecurity/trivy-db v0.0.0-20250723062229-56ec1e482238
27+
github.com/aquasecurity/trivy-db v0.0.0-20250731052236-c7c831e2254d
2828
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48
2929
github.com/aquasecurity/trivy-kubernetes v0.9.1
3030
github.com/aws/aws-sdk-go-v2 v1.37.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -829,8 +829,8 @@ github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gw
829829
github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY=
830830
github.com/aquasecurity/trivy-checks v1.11.3-0.20250604022615-9a7efa7c9169 h1:TckzIxUX7lZaU9f2lNxCN0noYYP8fzmSQf6a4JdV83w=
831831
github.com/aquasecurity/trivy-checks v1.11.3-0.20250604022615-9a7efa7c9169/go.mod h1:nT69xgRcBD4NlHwTBpWMYirpK5/Zpl8M+XDOgmjMn2k=
832-
github.com/aquasecurity/trivy-db v0.0.0-20250723062229-56ec1e482238 h1:ZT7cZan/iS/nD7D6CG4/AVdtqArKi9GtovlL4lEi/RY=
833-
github.com/aquasecurity/trivy-db v0.0.0-20250723062229-56ec1e482238/go.mod h1:upAJqDQkN5FdIJbtJMpokncGNhYAPGkpoCbaGciWPt4=
832+
github.com/aquasecurity/trivy-db v0.0.0-20250731052236-c7c831e2254d h1:Lc+p2CLARivVF48o7uRoFPaahNCvNFyBfeby0JqAMXo=
833+
github.com/aquasecurity/trivy-db v0.0.0-20250731052236-c7c831e2254d/go.mod h1:upAJqDQkN5FdIJbtJMpokncGNhYAPGkpoCbaGciWPt4=
834834
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI=
835835
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8=
836836
github.com/aquasecurity/trivy-kubernetes v0.9.1 h1:bSErQcavKXDh7XMwbGX7Vy//jR5+xhe/bOgfn9G+9lQ=

pkg/cache/fs.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package cache
22

33
import (
44
"encoding/json"
5+
"errors"
56
"os"
67
"path/filepath"
8+
"time"
79

810
"github.com/hashicorp/go-multierror"
911
bolt "go.etcd.io/bbolt"
@@ -12,6 +14,8 @@ import (
1214
"github.com/aquasecurity/trivy/pkg/fanal/types"
1315
)
1416

17+
const defaultFSCacheTimeout = 5 * time.Second
18+
1519
var _ Cache = &FSCache{}
1620

1721
type FSCache struct {
@@ -25,9 +29,15 @@ func NewFSCache(cacheDir string) (FSCache, error) {
2529
return FSCache{}, xerrors.Errorf("failed to create cache dir: %w", err)
2630
}
2731

28-
db, err := bolt.Open(filepath.Join(dir, "fanal.db"), 0o600, nil)
32+
db, err := bolt.Open(filepath.Join(dir, "fanal.db"), 0o600, &bolt.Options{
33+
Timeout: defaultFSCacheTimeout,
34+
})
2935
if err != nil {
30-
return FSCache{}, xerrors.Errorf("unable to open DB: %w", err)
36+
// Check if the error is due to timeout (database locked by another process)
37+
if errors.Is(err, bolt.ErrTimeout) {
38+
return FSCache{}, xerrors.Errorf("cache may be in use by another process: %w", err)
39+
}
40+
return FSCache{}, xerrors.Errorf("unable to open cache DB: %w", err)
3141
}
3242

3343
err = db.Update(func(tx *bolt.Tx) error {

0 commit comments

Comments
 (0)