代码之家  ›  专栏  ›  技术社区  ›  Saurabh Nanda

Haskell中可变但可锁定的数据结构?

  •  0
  • Saurabh Nanda  · 技术社区  · 5 年前

    Haskell中是否有一个标准的数据结构可以像 IORef MVar ? 以下是我要达到的目标:

    • AccessToken
    • 但是 访问令牌 可能会过期,并且这些线程中的一个将首先知道(因为它将获得 401 响应)。让我们称之为线程 T1
    • T1 将立即调用 refreshToken
      1. 尝试读取时,所有新线程都被阻止 --直到它焕然一新 在该共享数据结构中可用
      2. 401 ,在呼叫时被阻止 刷新令牌 功能。

    我已经用过 存储 以易变的方式。但是,我不确定是否应该使用 兆伏安 保护对 刷新令牌

    0 回复  |  直到 5 年前
        1
  •  6
  •   dfeuer    5 年前

    我不熟悉这个特定的API,但我觉得您可能只想将令牌和一个计数器存储在一个 MVar 带着令牌。每个需要令牌调用的线程 readMVar 为了得到它。

    tryTakeMVar 控制代币。如果失败了,那么其他线程已经控制了,这个线程返回到 . 如果成功,则检查计数器是否与预期相符。如果不是,其他线程已经刷新了令牌,它只是将其放回原处。如果是,则刷新令牌,增加计数器,并将这些放入 兆伏安 在继续前进之前。对于锁定协议,您需要像往常一样小心异常安全;有一些 有助于实现这一点的功能。

    正如我所描述的,该方案要求一个线程负责初始化。如果你只想在第一次需要的时候获得代币,你需要做一个小小的调整:存储a Maybe 兆伏安 ,初始化为 Nothing

    acquireToken refreshToken 分别获取令牌和刷新现有令牌。显然,如果这些操作实际上是以相同的方式进行的,则可以相应地进行调整。这个 restore

    newtype TokBox = TB (MVar (Maybe (Word, AccessToken)))
    
    newTokBox :: IO TokBox
    newTokBox = TB <$> newMVar Nothing
    
    -- | Get a (possibly expired) token and an action to use if that
    -- token is expired. The result
    -- should only be used once.
    getToken :: TokBox -> IO (AccessToken, IO ())
    getToken tb@(TB mv) = do
      contents <- readMVar mv
      case contents of
        Nothing -> refresh Nothing tb
        Just (_, t) -> pure (t, refresh contents tb)
    
    -- Refresh the access token, expecting the MVar to have particular contents.
    refresh :: Maybe (Word, AccessToken) -> TokBox -> IO ()
    refresh old (TB mv) =
      mask $ \restore ->
        tryTakeMVar mv >>= \case
          -- Another thread is refreshing
          Nothing -> pure ()
          Just cont
            -- Another thread refreshed; we restore the MVar
            | not $ sameContents cont old
            = putMVar mv cont
            | otherwise
            = (restore $ case cont of
                 Nothing -> do
                   tok <- acquireToken
                   putMVar mv (Just (0, tok))
                 Just (count, tok) -> do
                   tok' <- refreshToken tok
                   putMVar mv (Just (count + 1, tok')))
                    `onException`
                      putMVar cont
    
    sameContents :: Maybe (Word, a) -> Maybe (Word, b) -> Bool
    sameContents Nothing Nothing = True
    sameContents (Just (m, _)) (Just (n, _)) = m == n
    sameContents _ _ = False
    
    推荐文章