Skip to main content

rustfs_filemeta/
filemeta_inline.rs

1// Copyright 2024 RustFS 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 crate::error::{Error, Result};
16use crate::filemeta::msgp_decode::{prealloc_hint, read_exact_vec};
17use serde::{Deserialize, Serialize};
18use std::io::Cursor;
19use uuid::Uuid;
20
21#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
22pub struct InlineData(Vec<u8>);
23
24const INLINE_DATA_VER: u8 = 1;
25
26impl InlineData {
27    fn contains_key_by<F>(&self, mut should_remove: F) -> Result<bool>
28    where
29        F: FnMut(&[u8]) -> bool,
30    {
31        let buf = self.after_version();
32        if buf.is_empty() {
33            return Ok(false);
34        }
35
36        let mut scan_cur = Cursor::new(buf);
37        let mut scan_fields_len = rmp::decode::read_map_len(&mut scan_cur)? as usize;
38
39        while scan_fields_len > 0 {
40            scan_fields_len -= 1;
41
42            let str_len = rmp::decode::read_str_len(&mut scan_cur)? as usize;
43            let key_start = scan_cur.position() as usize;
44            let key_end = key_start + str_len;
45            let key = buf
46                .get(key_start..key_end)
47                .ok_or_else(|| Error::other("InlineData key out of range"))?;
48            scan_cur.set_position(key_end as u64);
49
50            let bin_len = rmp::decode::read_bin_len(&mut scan_cur)? as usize;
51            let value_start = scan_cur.position() as usize;
52            let value_end = value_start + bin_len;
53            if value_end > buf.len() {
54                return Err(Error::other("InlineData value out of range"));
55            }
56            scan_cur.set_position(value_end as u64);
57
58            if should_remove(key) {
59                return Ok(true);
60            }
61        }
62
63        Ok(false)
64    }
65
66    fn remove_keys_by<F>(&mut self, mut should_remove: F) -> Result<bool>
67    where
68        F: FnMut(&[u8]) -> bool,
69    {
70        let buf = self.after_version();
71        if buf.is_empty() {
72            return Ok(false);
73        }
74
75        let mut cur = Cursor::new(buf);
76        let mut fields_len = rmp::decode::read_map_len(&mut cur)? as usize;
77        let mut keys = Vec::with_capacity(prealloc_hint(fields_len));
78        let mut values = Vec::with_capacity(prealloc_hint(fields_len));
79        let mut found = false;
80
81        while fields_len > 0 {
82            fields_len -= 1;
83
84            let str_len = rmp::decode::read_str_len(&mut cur)? as usize;
85            let field_buf = read_exact_vec(&mut cur, str_len)?;
86
87            let bin_len = rmp::decode::read_bin_len(&mut cur)? as usize;
88            let start = cur.position() as usize;
89            let end = start + bin_len;
90            let value = buf
91                .get(start..end)
92                .ok_or_else(|| Error::other("InlineData value out of range"))?;
93            cur.set_position(end as u64);
94
95            if should_remove(field_buf.as_slice()) {
96                found = true;
97                continue;
98            }
99
100            keys.push(String::from_utf8(field_buf)?);
101            values.push(value.to_vec());
102        }
103
104        if !found {
105            return Ok(false);
106        }
107
108        if keys.is_empty() {
109            self.0 = Vec::new();
110            return Ok(true);
111        }
112
113        self.serialize(keys, values)?;
114        Ok(true)
115    }
116
117    fn remove_two_keys_by_bytes(&mut self, first_key: &[u8], second_key: &[u8]) -> Result<bool> {
118        let buf = self.after_version();
119        if buf.is_empty() {
120            return Ok(false);
121        }
122
123        let same = first_key == second_key;
124        let mut cur = Cursor::new(buf);
125        let mut fields_len = rmp::decode::read_map_len(&mut cur)? as usize;
126        let mut keys = Vec::with_capacity(prealloc_hint(fields_len) + 1);
127        let mut values = Vec::with_capacity(prealloc_hint(fields_len) + 1);
128        let mut found = false;
129
130        while fields_len > 0 {
131            fields_len -= 1;
132
133            let str_len = rmp::decode::read_str_len(&mut cur)? as usize;
134            let field_buf = read_exact_vec(&mut cur, str_len)?;
135
136            let bin_len = rmp::decode::read_bin_len(&mut cur)? as usize;
137            let start = cur.position() as usize;
138            let end = start + bin_len;
139            let value = buf
140                .get(start..end)
141                .ok_or_else(|| Error::other("InlineData value out of range"))?;
142            cur.set_position(end as u64);
143
144            let should_remove = if same {
145                field_buf.as_slice() == first_key
146            } else {
147                field_buf.as_slice() == first_key || field_buf.as_slice() == second_key
148            };
149
150            if should_remove {
151                found = true;
152                continue;
153            }
154
155            keys.push(String::from_utf8(field_buf)?);
156            values.push(value.to_vec());
157        }
158
159        if !found {
160            return Ok(false);
161        }
162
163        if keys.is_empty() {
164            self.0 = Vec::new();
165            return Ok(true);
166        }
167
168        self.serialize(keys, values)?;
169        Ok(true)
170    }
171
172    pub fn new() -> Self {
173        Self(Vec::new())
174    }
175    pub fn update(&mut self, buf: &[u8]) {
176        self.0 = buf.to_vec()
177    }
178    pub fn as_slice(&self) -> &[u8] {
179        self.0.as_slice()
180    }
181    pub fn version_ok(&self) -> bool {
182        if self.0.is_empty() {
183            return true;
184        }
185
186        self.0[0] > 0 && self.0[0] <= INLINE_DATA_VER
187    }
188
189    pub fn after_version(&self) -> &[u8] {
190        if self.0.is_empty() { &self.0 } else { &self.0[1..] }
191    }
192
193    pub fn entries(&self) -> Result<usize> {
194        if self.0.is_empty() || !self.version_ok() {
195            return Ok(0);
196        }
197
198        let buf = self.after_version();
199
200        let mut cur = Cursor::new(buf);
201
202        let fields_len = rmp::decode::read_map_len(&mut cur)?;
203
204        Ok(fields_len as usize)
205    }
206
207    pub fn find(&self, key: &str) -> Result<Option<Vec<u8>>> {
208        if self.0.is_empty() || !self.version_ok() {
209            return Ok(None);
210        }
211
212        let buf = self.after_version();
213
214        let mut cur = Cursor::new(buf);
215
216        let mut fields_len = rmp::decode::read_map_len(&mut cur)?;
217
218        while fields_len > 0 {
219            fields_len -= 1;
220
221            let str_len = rmp::decode::read_str_len(&mut cur)?;
222
223            let field_buff = read_exact_vec(&mut cur, str_len as usize)?;
224
225            let field = String::from_utf8(field_buff)?;
226
227            let bin_len = rmp::decode::read_bin_len(&mut cur)? as usize;
228            let start = cur.position() as usize;
229            let end = start + bin_len;
230            let value = buf
231                .get(start..end)
232                .ok_or_else(|| Error::other("InlineData value out of range"))?;
233            cur.set_position(end as u64);
234
235            if field.as_str() == key {
236                return Ok(Some(value.to_vec()));
237            }
238        }
239
240        Ok(None)
241    }
242
243    pub fn validate(&self) -> Result<()> {
244        if self.0.is_empty() {
245            return Ok(());
246        }
247
248        let buf = self.after_version();
249        let mut cur = Cursor::new(buf);
250
251        let mut fields_len = rmp::decode::read_map_len(&mut cur)?;
252
253        while fields_len > 0 {
254            fields_len -= 1;
255
256            let str_len = rmp::decode::read_str_len(&mut cur)?;
257
258            let field_buff = read_exact_vec(&mut cur, str_len as usize)?;
259
260            let field = String::from_utf8(field_buff)?;
261            if field.is_empty() {
262                return Err(Error::other("InlineData key empty"));
263            }
264
265            let bin_len = rmp::decode::read_bin_len(&mut cur)? as usize;
266            let start = cur.position() as usize;
267            let end = start + bin_len;
268            if end > buf.len() {
269                return Err(Error::other("InlineData value out of range"));
270            }
271            cur.set_position(end as u64);
272        }
273
274        Ok(())
275    }
276
277    pub fn replace(&mut self, key: &str, value: Vec<u8>) -> Result<()> {
278        if self.after_version().is_empty() {
279            let mut keys = Vec::with_capacity(1);
280            let mut values = Vec::with_capacity(1);
281
282            keys.push(key.to_owned());
283            values.push(value);
284
285            return self.serialize(keys, values);
286        }
287
288        let buf = self.after_version();
289        let mut cur = Cursor::new(buf);
290
291        let mut fields_len = rmp::decode::read_map_len(&mut cur)? as usize;
292        let mut keys = Vec::with_capacity(prealloc_hint(fields_len) + 1);
293        let mut values = Vec::with_capacity(prealloc_hint(fields_len) + 1);
294
295        let mut replaced = false;
296
297        while fields_len > 0 {
298            fields_len -= 1;
299
300            let str_len = rmp::decode::read_str_len(&mut cur)?;
301
302            let field_buff = read_exact_vec(&mut cur, str_len as usize)?;
303
304            let find_key = String::from_utf8(field_buff)?;
305
306            let bin_len = rmp::decode::read_bin_len(&mut cur)? as usize;
307            let start = cur.position() as usize;
308            let end = start + bin_len;
309            let find_value = buf
310                .get(start..end)
311                .ok_or_else(|| Error::other("InlineData value out of range"))?;
312            cur.set_position(end as u64);
313
314            if find_key.as_str() == key {
315                values.push(value.clone());
316                replaced = true
317            } else {
318                values.push(find_value.to_vec());
319            }
320
321            keys.push(find_key);
322        }
323
324        if !replaced {
325            keys.push(key.to_owned());
326            values.push(value);
327        }
328
329        self.serialize(keys, values)
330    }
331
332    pub fn remove_key(&mut self, key: &str) -> Result<bool> {
333        let key_bytes = key.as_bytes();
334        if !self.contains_key_by(|candidate| candidate == key_bytes)? {
335            return Ok(false);
336        }
337        self.remove_keys_by(|candidate| candidate == key_bytes)
338    }
339
340    pub fn remove(&mut self, remove_keys: Vec<Uuid>) -> Result<bool> {
341        let mut encoded_keys = Vec::with_capacity(remove_keys.len());
342        for key in remove_keys {
343            let mut buf = Uuid::encode_buffer();
344            encoded_keys.push(key.hyphenated().encode_lower(&mut buf).to_string().into_bytes());
345        }
346
347        self.remove_keys_by(|candidate| encoded_keys.iter().any(|key| candidate == key.as_slice()))
348    }
349
350    pub fn remove_two(&mut self, first: Uuid, second: Uuid) -> Result<bool> {
351        let mut first_buf = Uuid::encode_buffer();
352        let mut second_buf = Uuid::encode_buffer();
353        let first_key = first.hyphenated().encode_lower(&mut first_buf).as_bytes();
354        let second_key = second.hyphenated().encode_lower(&mut second_buf).as_bytes();
355        self.remove_two_keys_by_bytes(first_key, second_key)
356    }
357    fn serialize(&mut self, keys: Vec<String>, values: Vec<Vec<u8>>) -> Result<()> {
358        assert_eq!(keys.len(), values.len(), "InlineData serialize: keys/values not match");
359
360        if keys.is_empty() {
361            self.0 = Vec::new();
362            return Ok(());
363        }
364
365        let mut wr = Vec::new();
366
367        wr.push(INLINE_DATA_VER);
368
369        let map_len = keys.len();
370
371        rmp::encode::write_map_len(&mut wr, map_len as u32)?;
372
373        for i in 0..map_len {
374            rmp::encode::write_str(&mut wr, keys[i].as_str())?;
375            rmp::encode::write_bin(&mut wr, values[i].as_slice())?;
376        }
377
378        self.0 = wr;
379
380        Ok(())
381    }
382}
383
384#[cfg(test)]
385mod tests {
386    use super::*;
387
388    #[test]
389    fn remove_key_miss_keeps_inline_data_unchanged() {
390        let mut data = InlineData::new();
391        data.replace("keep", b"value".to_vec()).expect("seed inline data");
392        let before = data.as_slice().to_vec();
393
394        let removed = data.remove_key("missing").expect("remove_key should succeed");
395
396        assert!(!removed);
397        assert_eq!(data.as_slice(), before.as_slice());
398    }
399
400    #[test]
401    fn remove_two_removes_only_matching_keys() {
402        let first = Uuid::new_v4();
403        let second = Uuid::new_v4();
404        let keep = Uuid::new_v4();
405        let mut data = InlineData::new();
406        data.replace(first.hyphenated().to_string().as_str(), b"first".to_vec())
407            .expect("seed first key");
408        data.replace(second.hyphenated().to_string().as_str(), b"second".to_vec())
409            .expect("seed second key");
410        data.replace(keep.hyphenated().to_string().as_str(), b"keep".to_vec())
411            .expect("seed keep key");
412
413        let removed = data.remove_two(first, second).expect("remove_two should succeed");
414
415        assert!(removed);
416        assert_eq!(data.find(first.hyphenated().to_string().as_str()).expect("find first"), None);
417        assert_eq!(data.find(second.hyphenated().to_string().as_str()).expect("find second"), None);
418        assert_eq!(
419            data.find(keep.hyphenated().to_string().as_str()).expect("find keep"),
420            Some(b"keep".to_vec())
421        );
422    }
423}