File size: 2,713 Bytes
84d2a97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use std::ops::Deref;
use std::sync::Arc;

use atomic_refcell::AtomicRefCell;
use common::types::PointOffsetType;

use crate::payload_storage::payload_storage_enum::PayloadStorageEnum;
use crate::payload_storage::PayloadStorage;
use crate::types::{OwnedPayloadRef, Payload};

#[derive(Clone)]
pub struct PayloadProvider {
    payload_storage: Arc<AtomicRefCell<PayloadStorageEnum>>,
    empty_payload: Payload,
}

impl PayloadProvider {
    pub fn new(payload_storage: Arc<AtomicRefCell<PayloadStorageEnum>>) -> Self {
        Self {
            payload_storage,
            empty_payload: Default::default(),
        }
    }

    pub fn with_payload<F, G>(&self, point_id: PointOffsetType, callback: F) -> G
    where
        F: FnOnce(OwnedPayloadRef) -> G,
    {
        let payload_storage_guard = self.payload_storage.borrow();
        let payload_ptr_opt = match payload_storage_guard.deref() {
            #[cfg(feature = "testing")]
            PayloadStorageEnum::InMemoryPayloadStorage(s) => {
                s.payload_ptr(point_id).map(OwnedPayloadRef::from)
            }
            PayloadStorageEnum::SimplePayloadStorage(s) => {
                s.payload_ptr(point_id).map(OwnedPayloadRef::from)
            }
            // Warn: Possible panic here
            // Currently, it is possible that `read_payload` fails with Err,
            // but it seems like a very rare possibility which might only happen
            // if something is wrong with disk or storage is corrupted.
            //
            // In both cases it means that service can't be of use any longer.
            // It is as good as dead. Therefore it is tolerable to just panic here.
            // Downside is - API user won't be notified of the failure.
            // It will just timeout.
            //
            // The alternative:
            // Rewrite condition checking code to support error reporting.
            // Which may lead to slowdown and assumes a lot of changes.
            PayloadStorageEnum::OnDiskPayloadStorage(s) => s
                .read_payload(point_id)
                .unwrap_or_else(|err| panic!("Payload storage is corrupted: {err}"))
                .map(OwnedPayloadRef::from),
            PayloadStorageEnum::MmapPayloadStorage(s) => {
                let payload = s
                    .get(point_id)
                    .unwrap_or_else(|err| panic!("Payload storage is corrupted: {err}"));
                Some(OwnedPayloadRef::from(payload))
            }
        };

        let payload = if let Some(payload_ptr) = payload_ptr_opt {
            payload_ptr
        } else {
            OwnedPayloadRef::from(&self.empty_payload)
        };

        callback(payload)
    }
}