System resource cache - #5289
Conversation
Signed-off-by: Jono Yang <jyang@nexb.com>
* Use sha256 instead of md5 Signed-off-by: Jono Yang <jyang@nexb.com>
Signed-off-by: Jono Yang <jyang@nexb.com>
Signed-off-by: Jono Yang <jyang@nexb.com>
* Create envvar for controlling whether or not the scan results cache is used Signed-off-by: Jono Yang <jyang@nexb.com>
Signed-off-by: Jono Yang <jyang@nexb.com>
Signed-off-by: Jono Yang <jyang@nexb.com>
Signed-off-by: Jono Yang <jyang@nexb.com>
Signed-off-by: Jono Yang <jyang@nexb.com>
Signed-off-by: Jono Yang <jyang@nexb.com>
Signed-off-by: Jono Yang <jyang@nexb.com>
Signed-off-by: Jono Yang <jyang@nexb.com>
Signed-off-by: Jono Yang <jyang@nexb.com>
a1aa058 to
60ee685
Compare
Signed-off-by: Jono Yang <jyang@nexb.com>
Signed-off-by: Jono Yang <jyang@nexb.com>
e965307 to
1247f39
Compare
* The runner cannot instantiate a cryptography library of some kind Signed-off-by: Jono Yang <jyang@nexb.com>
There was a problem hiding this comment.
@JonoYang LGTM! Thanks++
See some of my comments for your consideration.
I also did some basic scans which shows negligible performance impact on cache creation and significant performance gain from using cached results. But we should probably do some proper benchmarks to test the performance gains too.
The archives I used for running the benchmarks:
- https://github.com/syncthing/syncthing/archive/refs/tags/v2.1.2.tar.gz
- https://github.com/syncthing/syncthing/archive/refs/tags/v2.1.3.tar.gz
First scan of v2.1.2 without --use-cached-results:
scancode -clipeu syncthing-2.1.2.tar.gz-extract/ --json-pp syncthing-2.1.2-clipeu.json -n 6
Setup plugins...
Collect file inventory...
Scan files for: info, packages, licenses, copyrights, emails, urls with 6 process(es)...
[####################] 1868
Scanning done.
Summary: info, packages, licenses, copyrights, emails, urls with 6 process(es)
Errors count: 0
Scan Speed: 7.71 files/sec. 110.88 KB/sec.--use-cached-results
Initial counts: 1133 resource(s): 934 file(s) and 199 directorie(s)
Final counts: 1133 resource(s): 934 file(s) and 199 directorie(s) for 13.11 MB
Timings:
scan_start: 2026-09-07T100805.133779
scan_end: 2026-09-07T101008.901230
setup_scan:licenses: 2.45s
setup: 2.45s
inventory: 0.11s
scan:packages: 0.13s
scan: 121.10s
output:json-pp: 0.34s
output: 0.34s
total: 124.13s
Removing temporary files...done.
First scan of v2.1.3 without --use-cached-results:
scancode -clipeu syncthing-2.1.3.tar.gz-extract/ --json-pp syncthing-2.1.3-clipeu.json -n 6
Setup plugins...
Collect file inventory...
Scan files for: info, packages, licenses, copyrights, emails, urls with 6 process(es)...
[####################] 1866
Scanning done.
Summary: info, packages, licenses, copyrights, emails, urls with 6 process(es)
Errors count: 0
Scan Speed: 7.40 files/sec. 106.58 KB/sec.
Initial counts: 1132 resource(s): 933 file(s) and 199 directorie(s)
Final counts: 1132 resource(s): 933 file(s) and 199 directorie(s) for 13.12 MB
Timings:
scan_start: 2026-09-07T101019.832652
scan_end: 2026-09-07T101228.601000
setup_scan:licenses: 2.47s
setup: 2.47s
inventory: 0.11s
scan:packages: 0.11s
scan: 126.07s
output:json-pp: 0.32s
output: 0.32s
total: 129.11s
Scan of v2.1.2 with --use-cached-results (only creating cache):
scancode -clipeu syncthing-2.1.2.tar.gz-extract/ --json-pp syncthing-2.1.2-clipeu.json -n 6 --use-cached-results
Setup plugins...
Collect file inventory...
Scan files for: info, packages, licenses, copyrights, emails, urls with 6 process(es)...
[####################] 1868
Scanning done.
Summary: info, packages, licenses, copyrights, emails, urls with 6 process(es)
Errors count: 0
Scan Speed: 7.70 files/sec. 110.63 KB/sec.
Initial counts: 1133 resource(s): 934 file(s) and 199 directorie(s)
Final counts: 1133 resource(s): 934 file(s) and 199 directorie(s) for 13.11 MB
Timings:
scan_start: 2026-09-07T101433.426523
scan_end: 2026-09-07T101637.529302
setup_scan:licenses: 2.49s
setup: 2.49s
inventory: 0.12s
scan:packages: 0.12s
scan: 121.38s
output:json-pp: 0.34s
output: 0.34s
total: 124.46s
Removing temporary files...done.
Scan of v2.1.3 with --use-cached-results (using cached results on another version with highly similar files):
scancode -clipeu syncthing-2.1.3.tar.gz-extract/ --json-pp syncthing-2.1.3-clipeu.json -n 6 --use-cached-results
Setup plugins...
Collect file inventory...
Scan files for: info, packages, licenses, copyrights, emails, urls with 6 process(es)...
[####################] 1866
Scanning done.
Summary: info, packages, licenses, copyrights, emails, urls with 6 process(es)
Errors count: 0
Scan Speed: 45.50 files/sec. 655.31 KB/sec.
Initial counts: 1132 resource(s): 933 file(s) and 199 directorie(s)
Final counts: 1132 resource(s): 933 file(s) and 199 directorie(s) for 13.12 MB
Timings:
scan_start: 2026-09-07T102406.378978
scan_end: 2026-09-07T102429.571458
setup_scan:licenses: 2.45s
setup: 2.46s
inventory: 0.11s
scan:packages: 0.13s
scan: 20.50s
output:json-pp: 0.33s
output: 0.33s
total: 23.55s
Removing temporary files...done.
Scan of v2.1.2 with --use-cached-results (using cached results on a same version with exactly similar files):
scancode -clipeu syncthing-2.1.2.tar.gz-extract/ --json-pp syncthing-2.1.2-clipeu.json -n 6 --use-cached-results
Setup plugins...
Collect file inventory...
Scan files for: info, packages, licenses, copyrights, emails, urls with 6 process(es)...
[####################] 1868
Scanning done.
Summary: info, packages, licenses, copyrights, emails, urls with 6 process(es)
Errors count: 0
Scan Speed: 1563.51 files/sec. 21.95 MB/sec.
Initial counts: 1133 resource(s): 934 file(s) and 199 directorie(s)
Final counts: 1133 resource(s): 934 file(s) and 199 directorie(s) for 13.11 MB
Timings:
scan_start: 2026-09-07T102440.089470
scan_end: 2026-09-07T102443.410571
setup_scan:licenses: 2.50s
setup: 2.50s
inventory: 0.11s
scan:packages: 0.13s
scan: 0.60s
output:json-pp: 0.33s
output: 0.33s
total: 3.67s
Removing temporary files...done.
Summary:
- scan of
v2.1.2: 124.13s - scan of
v2.1.3: 129.11s - scan of
v2.1.2only creating cache: 124.46s (negligible difference) - scan of
v2.1.3, using cached results on another version with highly similar files: 23.55s - scan of
v2.1.2, using cached results on a same version with exactly similar files: 3.67s
| return hasher | ||
|
|
||
|
|
||
| def compute_results_cache_index(location, filename): |
There was a problem hiding this comment.
Can this be reused from functions in commoncode.hash? The code there was updated to work on chunks a while ago too.
|
|
||
| def get_results_cache_directory_location(results_cache_index, results_cache_dir=results_cache_dir): | ||
| """ | ||
| Return the location of the directory containing the cache files for a given |
There was a problem hiding this comment.
Should we include an example results_cache_index string in the docstring?
| When run as a stand-alone release, the results cache is tied to specific | ||
| ScanCode toolkit versions. When run in development mode, the cache is stored | ||
| in the `scancode-toolkit/.cache` directory. | ||
|
|
There was a problem hiding this comment.
Should we include some functionality to re-compute the cache for a file based on data structure changes caused by different versions of scancode, or different CLI options used with different output data formats? There is some discussion on this at #3941
We need to check that we atleast handle the errors resulting out of this. Additionally it would be nice to somehow include the data format versions in the index cache too, smartly avoiding cache recompute whenever possible.
Output data formats are not always changes based on scancode versions, and an update in the output data format version also doesn't correspond to updates in all the scanner output data. So we need to probably compute a hash based on all the data fields present for a particular scanner data based on the keys present in the mapping and include this in the index file path? This would cover both variations caused by scancode version changes and CLI options used.
This is an enhancement though, so feel free to mark this out of scope.
| @click.option('--use-cached-results', | ||
| is_flag=True, | ||
| default=False, | ||
| hidden=True, |
There was a problem hiding this comment.
We could leave this as-is and not hidden, as there is an EXPERIMENTAL tag in the help text already. We want more people to see and test out the functionality probably, what do you think?
| hidden=True, | ||
| help_group=cliutils.MISC_GROUP, sort_order=1000, cls=PluggableCommandLineOption) | ||
|
|
||
| @click.option('--use-cached-results', |
There was a problem hiding this comment.
Was just wondering if this is the best name since this option enables both the creation of the cache and the use of cached results and this name only indicates the latter.
Alternatives could be: --use-results-cache, --cache-results, --cache but I'm not sure what to choose too.
There was a problem hiding this comment.
One other option is to use two other options one to create the cache and the other to use the cached results, but using just one option is probably much better if there are no large performance implications.
| is_flag=True, | ||
| default=False, | ||
| hidden=True, | ||
| help='(EXPERIMENTAL) ScanCode will use cached results during scan time.', |
There was a problem hiding this comment.
We need to highlight in the help text also that this option both:
- caches scan results from scans
- uses cached scan results
This PR introduces a cache for the results of scanners run by scancode. The
scancode,scan_codebase, andscan_resourcefunctions have been updated to look for cached scan results to reuse before scanning. The cache is updated after scanning, if it was required.This is related to #3941 #4556