1 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 // SPDX-License-Identifier: Apache-2.0
3 
4 use std::{io::copy, io::prelude::*};
5 
6 use failure::Error;
7 use log::info;
8 use rmp_serde::Serializer;
9 use serde::Serialize;
10 
11 use crate::store::base::Store;
12 
13 const CACHE_VERSION: &[u8] = b"askalono-04";
14 
15 impl 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.
from_cache<R>(mut readable: R) -> Result<Store, Error> where R: Read + Sized,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             failure::bail!("cache version mismatch");
32         }
33 
34         #[cfg(not(feature = "gzip"))]
35         let dec = zstd::Decoder::new(readable)?;
36         #[cfg(feature = "gzip")]
37         let dec = flate2::read::GzDecoder::new(readable);
38 
39         let store = rmp_serde::decode::from_read(dec)?;
40         Ok(store)
41     }
42 
43     /// Serialize the current store.
44     ///
45     /// The output will be a MessagePack'd gzip'd or zstd'd binary stream that should be
46     /// written to disk.
to_cache<W>(&self, mut writable: W) -> Result<(), Error> where W: Write + Sized,47     pub fn to_cache<W>(&self, mut writable: W) -> Result<(), Error>
48     where
49         W: Write + Sized,
50     {
51         let buf = {
52             // This currently sits around 3.7MiB, so go up to 4 to fit comfortably
53             let mut buf = Vec::with_capacity(4 * 1024 * 1024);
54             let mut serializer = Serializer::new(&mut buf);
55             self.serialize(&mut serializer)?;
56             buf
57         };
58 
59         info!("Pre-compressed output is {} bytes", buf.len());
60 
61         writable.write_all(CACHE_VERSION)?;
62 
63         #[cfg(not(feature = "gzip"))]
64         let mut enc = zstd::Encoder::new(writable, 21)?;
65         #[cfg(feature = "gzip")]
66         let mut enc = flate2::write::GzEncoder::new(writable, flate2::Compression::default());
67 
68         copy(&mut buf.as_slice(), &mut enc)?;
69         enc.finish()?;
70 
71         Ok(())
72     }
73 }
74