shmipc/
config.rs

1// Copyright 2025 CloudWeGo Authors
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 std::{fmt::Debug, time::Duration};
16
17use anyhow::anyhow;
18
19use crate::{
20    buffer::manager::BUFFER_HEADER_SIZE,
21    consts::{DEFAULT_QUEUE_CAP, DEFAULT_SHARE_MEMORY_CAP, MemMapType, SESSION_REBUILD_INTERVAL},
22};
23
24#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
25pub struct SizePercentPair {
26    pub size: u32,
27    pub percent: u32,
28}
29
30#[derive(Clone, Debug)]
31/// Config is used to tune the shmipc session
32pub struct Config {
33    /// connection_write_timeout is meant to be a "safety value" timeout after
34    /// which we will suspect a problem with the underlying connection and
35    /// close it. This is only applied to writes, where there's generally
36    /// an expectation that things will move along quickly.
37    pub connection_write_timeout: Duration,
38
39    pub connection_read_timeout: Option<Duration>,
40
41    pub connection_timeout: Option<Duration>,
42
43    /// initialize_timeout is meant timeout during server and client exchange config phase
44    pub initialize_timeout: Duration,
45
46    /// the max number of pending request
47    pub queue_cap: u32,
48
49    /// share memory path of the underlying queue
50    pub queue_path: String,
51
52    /// the capacity of buffer in share memory
53    pub share_memory_buffer_cap: u32,
54
55    /// the share memory path prefix of buffer
56    pub share_memory_path_prefix: String,
57
58    /// guess request or response's size for improving performance, and the default value is 4096
59    pub buffer_slice_sizes: Vec<SizePercentPair>,
60
61    /// mmap map type, MemMapTypeDevShmFile or MemMapTypeMemFd (server set)
62    pub mem_map_type: MemMapType,
63
64    /// client rebuild session interval
65    pub rebuild_interval: Duration,
66
67    pub max_stream_num: usize,
68}
69
70impl Default for Config {
71    fn default() -> Self {
72        Self::new()
73    }
74}
75
76impl Config {
77    pub fn new() -> Self {
78        Self {
79            connection_write_timeout: Duration::from_secs(10),
80            connection_read_timeout: None,
81            connection_timeout: None,
82            initialize_timeout: Duration::from_millis(1000),
83            queue_cap: DEFAULT_QUEUE_CAP,
84            queue_path: "/dev/shm/shmipc_queue".to_owned(),
85            share_memory_buffer_cap: DEFAULT_SHARE_MEMORY_CAP,
86            share_memory_path_prefix: "/dev/shm/shmipc".to_owned(),
87            buffer_slice_sizes: vec![
88                SizePercentPair {
89                    size: 8192 - BUFFER_HEADER_SIZE,
90                    percent: 50,
91                },
92                SizePercentPair {
93                    size: 32 * 1024 - BUFFER_HEADER_SIZE,
94                    percent: 30,
95                },
96                SizePercentPair {
97                    size: 128 * 1024 - BUFFER_HEADER_SIZE,
98                    percent: 20,
99                },
100            ],
101            mem_map_type: MemMapType::MemMapTypeMemFd,
102            rebuild_interval: SESSION_REBUILD_INTERVAL,
103            max_stream_num: 4096,
104        }
105    }
106
107    pub fn verify(&self) -> Result<(), anyhow::Error> {
108        if self.share_memory_buffer_cap < (1 << 20) {
109            return Err(anyhow!(
110                "share memory size is too small:{}, must greater than {}",
111                self.share_memory_buffer_cap,
112                1 << 20
113            ));
114        }
115        if self.buffer_slice_sizes.is_empty() {
116            return Err(anyhow!("buffer_slice_sizes could not be nil"));
117        }
118
119        let mut sum = 0;
120        for pair in self.buffer_slice_sizes.iter() {
121            sum += pair.percent;
122            if pair.size > self.share_memory_buffer_cap {
123                return Err(anyhow!(
124                    "buffer_slice_sizes's size:{} couldn't greater than share_memory_buffer_cap:{}",
125                    pair.size,
126                    self.share_memory_buffer_cap
127                ));
128            }
129
130            #[cfg(any(target_arch = "arm", target_arch = "arm64ec"))]
131            if pair.size % 4 != 0 {
132                return Err(anyhow!(
133                    "the size_percent_pair.size must be a multiple of 4"
134                ));
135            }
136        }
137
138        if sum != 100 {
139            return Err(anyhow!(
140                "the sum of buffer_slice_sizes's percent should be 100",
141            ));
142        }
143
144        #[cfg(any(target_arch = "arm", target_arch = "arm64ec"))]
145        if self.queue_cap % 8 != 0 {
146            return Err(anyhow!("the queue_cap must be a multiple of 8"));
147        }
148
149        if self.share_memory_path_prefix.is_empty() || self.queue_path.is_empty() {
150            return Err(anyhow!("buffer path or queue path could not be nil"));
151        }
152
153        #[cfg(not(target_os = "linux"))]
154        {
155            return Err(anyhow!("shmipc just support linux OS now"));
156        }
157
158        #[cfg(not(any(target_arch = "x86_64", target_arch = "arm64ec")))]
159        {
160            return Err(anyhow!("shmipc just support amd64 or arm64 arch"));
161        }
162
163        Ok(())
164    }
165}