Kaynağa Gözat

Better client side error handling.

Jing Yang 4 yıl önce
ebeveyn
işleme
3e6e6a36bd
1 değiştirilmiş dosya ile 18 ekleme ve 3 silme
  1. 18 3
      kvraft/src/client.rs

+ 18 - 3
kvraft/src/client.rs

@@ -25,7 +25,12 @@ impl Clerk {
     pub fn get(&mut self, key: String) -> Option<String> {
         let (init, inner) = (&self.init, &mut self.inner);
         init.call_once(|| inner.commit_sentinel());
-        inner.get(key, Default::default())
+        loop {
+            match inner.get(key.clone(), Default::default()) {
+                Some(val) => return val,
+                None => {}
+            }
+        }
     }
 
     pub fn put(&mut self, key: String, value: String) -> Option<()> {
@@ -140,18 +145,28 @@ impl ClerkInner {
         None
     }
 
+    /// This function returns None when
+    /// 1. No KVServer can be reached, or
+    /// 2. No KVServer claimed to be the leader, or
+    /// 3. When the KVServer committed the request but it was not passed
+    /// back to the clerk. We must retry with a new unique_id.
+    ///
+    /// In all 3 cases the request can be retried.
+    ///
+    /// This function do not expect a Conflict request with the same unique_id.
     pub fn get(
         &mut self,
         key: String,
         options: KVRaftOptions,
-    ) -> Option<String> {
+    ) -> Option<Option<String>> {
         let args = GetArgs {
             key,
             unique_id: self.unique_id.inc(),
         };
         let reply: GetReply = self.call_rpc(GET, args, options.max_retry)?;
         match reply.result {
-            Ok(val) => val,
+            Ok(val) => Some(val),
+            Err(KVError::Conflict) => panic!("We should never see a conflict."),
             _ => None,
         }
     }