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
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use std::{self, str::FromStr};
use trackable;
use trackable::error::ErrorKindExt;

/// crate固有のエラー型.
#[derive(Debug, Clone, TrackableError)]
pub struct Error(trackable::error::TrackableError<ErrorKind>);
impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Self {
        if let Some(e) = e.get_ref().and_then(|e| e.downcast_ref::<Error>()).cloned() {
            e
        } else if e.kind() == std::io::ErrorKind::InvalidInput {
            ErrorKind::InvalidInput.cause(e).into()
        } else {
            ErrorKind::Other.cause(e).into()
        }
    }
}
impl From<Error> for std::io::Error {
    fn from(e: Error) -> Self {
        if *e.kind() == ErrorKind::InvalidInput {
            std::io::Error::new(std::io::ErrorKind::InvalidInput, e)
        } else {
            std::io::Error::new(std::io::ErrorKind::Other, e)
        }
    }
}
impl<T> From<std::sync::PoisonError<T>> for Error {
    fn from(e: std::sync::PoisonError<T>) -> Self {
        ErrorKind::Other.cause(e.to_string()).into()
    }
}

/// 発生し得るエラーの種別.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ErrorKind {
    /// リクエストキューが詰まっている、等の過負荷状態.
    ///
    /// また、初期化処理中の場合にも、このエラーが返される.
    ///
    /// # 典型的な対応策
    ///
    /// - 利用者が時間をおいてリトライする
    /// - 優先度が低いリクエストの新規発行をしばらく控える
    DeviceBusy,

    /// デバイス(の管理スレッド)が停止しており、利用不可能.
    ///
    /// 正常・異常に関わらず、停止後のデバイスにリクエストが
    /// 発行された場合には、このエラーが返される.
    ///
    /// # 典型的な対応策
    ///
    /// - デバイスを再起動する
    DeviceTerminated,

    /// ストレージに空き容量がない.
    ///
    /// # 典型的な対応策
    ///
    /// - 利用者が不要なlumpを削除する
    /// - ストレージの容量を増やした上で、初期化・再構築を行う
    StorageFull,

    /// ストレージが破損している.
    ///
    /// ジャーナル領域のチェックサム検証が失敗した場合等にこのエラーが返される.
    ///
    /// # 典型的な対応策
    ///
    /// - もし人手で復旧可能な場合には復旧する
    /// - それが無理であれば、諦めて初期化(全削除)を行う
    StorageCorrupted,

    /// 入力が不正.
    ///
    /// # 典型的な対応策
    ///
    /// - 利用者側のプログラムを修正して入力を正しくする
    InvalidInput,

    /// 内部状態が不整合に陥っている.
    ///
    /// プログラムにバグがあることを示している.
    ///
    /// # 典型的な対応策
    ///
    /// - バグ修正を行ってプログラムを更新する
    InconsistentState,

    /// 過負荷のため、リクエストはドロップされた.
    ///
    /// # 典型的な対応策
    ///
    /// - 負荷の高い時間を避けてもう一度試す
    RequestDropped,

    /// 過負荷のため、リクエストは拒否された.
    ///
    /// # 典型的な対応策
    ///
    /// - 負荷の高い時間を避けてもう一度試す
    RequestRefused,

    /// その他エラー.
    ///
    /// E.g., I/Oエラー
    ///
    /// # 典型的な対応策
    ///
    /// - 利用者側で(指数バックオフ等を挟みつつ)何度かリトライ
    ///   - それでもダメなら、致命的な異常が発生していると判断
    Other,
}
impl trackable::error::ErrorKind for ErrorKind {}

impl std::fmt::Display for ErrorKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ErrorKind::StorageFull => write!(f, "StorageFull"),
            ErrorKind::StorageCorrupted => write!(f, "StorageCorrupted"),
            ErrorKind::DeviceBusy => write!(f, "DeviceBusy"),
            ErrorKind::DeviceTerminated => write!(f, "DeviceTerminated"),
            ErrorKind::InvalidInput => write!(f, "InvalidInput"),
            ErrorKind::InconsistentState => write!(f, "InconsistentState"),
            ErrorKind::RequestDropped => write!(f, "RequestDropped"),
            ErrorKind::RequestRefused => write!(f, "RequestRefused"),
            ErrorKind::Other => write!(f, "Other"),
        }
    }
}

impl FromStr for ErrorKind {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let kind = match s {
            "StorageFull" => ErrorKind::StorageFull,
            "StorageCorrupted" => ErrorKind::StorageCorrupted,
            "DeviceBusy" => ErrorKind::DeviceBusy,
            "DeviceTerminated" => ErrorKind::DeviceTerminated,
            "InvalidInput" => ErrorKind::InvalidInput,
            "RequestDropped" => ErrorKind::RequestDropped,
            "RequestRefused" => ErrorKind::RequestRefused,
            "InconsistentState" => ErrorKind::InconsistentState,
            "Other" => ErrorKind::Other,
            _ => return Err(()),
        };
        Ok(kind)
    }
}