scancode_rust/askalono/store/
cache.rs

1// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{io::copy, io::prelude::*};
5
6use anyhow::Error;
7use log::info;
8use rmp_serde::Serializer;
9use serde::Serialize;
10
11use crate::askalono::store::base::Store;
12
13const CACHE_VERSION: &[u8] = b"askalono-04";
14
15impl Store {
16    /// Create a store from a cache file.
17    ///
18    /// This method is highly useful for quickly loading a cache, as creating
19    /// one from text data is rather slow. This method can typically load
20    /// the full SPDX set from disk in 200-300 ms. The cache will be
21    /// sanity-checked to ensure it was generated with a similar version of
22    /// askalono.
23    pub fn from_cache<R>(mut readable: R) -> Result<Store, Error>
24    where
25        R: Read + Sized,
26    {
27        let mut header = [0u8; 11];
28        readable.read_exact(&mut header)?;
29
30        if header != CACHE_VERSION {
31            anyhow::bail!(
32                "cache version mismatch; expected '{}', found '{}'",
33                String::from_utf8_lossy(CACHE_VERSION),
34                String::from_utf8_lossy(&header)
35            );
36        }
37
38        #[cfg(not(feature = "gzip"))]
39        let dec = zstd::Decoder::new(readable)?;
40        #[cfg(feature = "gzip")]
41        let dec = flate2::read::GzDecoder::new(readable);
42
43        let store = rmp_serde::decode::from_read(dec)?;
44        Ok(store)
45    }
46
47    /// Serialize the current store.
48    ///
49    /// The output will be a MessagePack'd gzip'd or zstd'd binary stream that should be
50    /// written to disk.
51    pub fn to_cache<W>(&self, mut writable: W) -> Result<(), Error>
52    where
53        W: Write + Sized,
54    {
55        let buf = {
56            // This currently sits around 3.7MiB, so go up to 4 to fit comfortably
57            let mut buf = Vec::with_capacity(4 * 1024 * 1024);
58            let mut serializer = Serializer::new(&mut buf);
59            self.serialize(&mut serializer)?;
60            buf
61        };
62
63        info!("Pre-compressed output is {} bytes", buf.len());
64
65        writable.write_all(CACHE_VERSION)?;
66
67        #[cfg(not(feature = "gzip"))]
68        let mut enc = zstd::Encoder::new(writable, 21)?;
69        #[cfg(feature = "gzip")]
70        let mut enc = flate2::write::GzEncoder::new(writable, flate2::Compression::default());
71
72        copy(&mut buf.as_slice(), &mut enc)?;
73        enc.finish()?;
74
75        Ok(())
76    }
77}