common_meta/snapshot/
file.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use common_time::util::current_time_millis;
16use flexbuffers::{FlexbufferSerializer, Reader};
17use serde::{Deserialize, Serialize};
18use snafu::ResultExt;
19
20use crate::error::{
21    DeserializeFlexbuffersSnafu, ReadFlexbuffersSnafu, Result, SerializeFlexbuffersSnafu,
22};
23use crate::snapshot::FileFormat;
24
25/// The layout of the backup file.
26#[derive(Debug, PartialEq, Serialize, Deserialize)]
27pub(crate) struct Document {
28    metadata: Metadata,
29    content: Content,
30}
31
32impl Document {
33    /// Creates a new document.
34    pub fn new(metadata: Metadata, content: Content) -> Self {
35        Self { metadata, content }
36    }
37
38    fn serialize_to_flexbuffer(&self) -> Result<Vec<u8>> {
39        let mut builder = FlexbufferSerializer::new();
40        self.serialize(&mut builder)
41            .context(SerializeFlexbuffersSnafu)?;
42        Ok(builder.take_buffer())
43    }
44
45    /// Converts the [`Document`] to a bytes.
46    pub(crate) fn to_bytes(&self, format: &FileFormat) -> Result<Vec<u8>> {
47        match format {
48            FileFormat::FlexBuffers => self.serialize_to_flexbuffer(),
49        }
50    }
51
52    fn deserialize_from_flexbuffer(data: &[u8]) -> Result<Self> {
53        let reader = Reader::get_root(data).context(ReadFlexbuffersSnafu)?;
54        Document::deserialize(reader).context(DeserializeFlexbuffersSnafu)
55    }
56
57    /// Deserializes the [`Document`] from a bytes.
58    pub(crate) fn from_slice(format: &FileFormat, data: &[u8]) -> Result<Self> {
59        match format {
60            FileFormat::FlexBuffers => Self::deserialize_from_flexbuffer(data),
61        }
62    }
63
64    /// Converts the [`Document`] to a [`MetadataContent`].
65    pub(crate) fn into_metadata_content(self) -> Result<MetadataContent> {
66        match self.content {
67            Content::Metadata(metadata) => Ok(metadata),
68        }
69    }
70}
71
72/// The metadata of the backup file.
73#[derive(Debug, PartialEq, Serialize, Deserialize)]
74pub(crate) struct Metadata {
75    // UNIX_EPOCH in milliseconds.
76    created_timestamp_mills: i64,
77}
78
79impl Metadata {
80    /// Create a new metadata.
81    ///
82    /// The `created_timestamp_mills` will be the current time in milliseconds.
83    pub fn new() -> Self {
84        Self {
85            created_timestamp_mills: current_time_millis(),
86        }
87    }
88}
89
90/// The content of the backup file.
91#[derive(Debug, PartialEq, Serialize, Deserialize)]
92pub(crate) enum Content {
93    Metadata(MetadataContent),
94}
95
96/// The content of the backup file.
97#[derive(Debug, PartialEq, Serialize, Deserialize)]
98pub(crate) struct MetadataContent {
99    values: Vec<KeyValue>,
100}
101
102impl MetadataContent {
103    /// Create a new metadata content.
104    pub fn new(values: impl IntoIterator<Item = KeyValue>) -> Self {
105        Self {
106            values: values.into_iter().collect(),
107        }
108    }
109
110    /// Returns an iterator over the key-value pairs.
111    pub fn into_iter(self) -> impl Iterator<Item = KeyValue> {
112        self.values.into_iter()
113    }
114}
115
116/// The key-value pair of the backup file.
117#[derive(Debug, PartialEq, Serialize, Deserialize)]
118pub(crate) struct KeyValue {
119    pub key: Vec<u8>,
120    pub value: Vec<u8>,
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126
127    #[test]
128    fn test_document() {
129        let document = Document::new(
130            Metadata::new(),
131            Content::Metadata(MetadataContent::new(vec![KeyValue {
132                key: b"key".to_vec(),
133                value: b"value".to_vec(),
134            }])),
135        );
136
137        let bytes = document.to_bytes(&FileFormat::FlexBuffers).unwrap();
138        let document_deserialized = Document::from_slice(&FileFormat::FlexBuffers, &bytes).unwrap();
139        assert_eq!(
140            document.metadata.created_timestamp_mills,
141            document_deserialized.metadata.created_timestamp_mills
142        );
143        assert_eq!(document.content, document_deserialized.content);
144    }
145}