Skip to content

Commit e20e767

Browse files
iamirzhanmeta-codesync[bot]
authored andcommitted
Handle errors on server
Summary: For the "synchronous" write, clients got the handle and constantly check the result of the write. If write fails for some reason, they are notified about the failure getting the exception. For the async write clients don't track the result. If the write fails for some reason this should be unrecoverable failure and we mark database as broken. Reviewed By: malanka Differential Revision: D91677007 fbshipit-source-id: 678fb21fc7619197bc9099c58d38809321baf2ab
1 parent 1c9f2e7 commit e20e767

2 files changed

Lines changed: 40 additions & 20 deletions

File tree

glean/db/Glean/Database/Types.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ data WriteJob
160160
, writeContentIO :: IO WriteContent
161161
, writeDone :: MVar (Either SomeException Subst)
162162
, writeStart :: Point
163+
, writeFailureIrrecoverable :: Bool
164+
-- ^ If False, clients are supposed to check the write
165+
-- and handle the result.
166+
-- If True, the write is fully handled by server.
167+
-- In case of an error, the db will be marked as 'broken'
163168
}
164169
| WriteCheckpoint
165170
{ writeCheckpoint :: IO ()

glean/db/Glean/Database/Writes.hs

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ import Data.HashMap.Strict (HashMap)
5454
import qualified Data.HashMap.Strict as HashMap
5555
import qualified Data.Map as Map
5656
import qualified Data.Monoid as Monoid
57-
import Data.Text as Text (Text)
57+
import Data.Text as Text (Text, pack)
5858
import qualified Data.Text.Encoding as Text
5959
import qualified Data.UUID as UUID
6060
import qualified Data.UUID.V4 as UUID
@@ -72,12 +72,14 @@ import Util.Log
7272
import Util.STM
7373

7474
import Glean.Database.BatchLocation as BatchLocation
75+
import qualified Glean.Database.Catalog as Catalog
7576
import Glean.Database.Exception
7677
import Glean.Database.Open
7778
import Glean.Database.Schema.Types
7879
import Glean.Database.Trace
7980
import Glean.Database.Write.Batch
8081
import Glean.Database.Types
82+
import Glean.Internal.Types as Thrift
8183
import qualified Glean.RTS.Foreign.Subst as Subst
8284
import Glean.RTS.Foreign.Ownership (DefineOwnership)
8385
import qualified Glean.ServerConfig.Types as ServerConfig
@@ -127,6 +129,14 @@ writerThread env WriteQueues{..} = mask $ \restore ->
127129
addStatValueType "glean.db.write.failed" (writeSize `div` k) Sum
128130
else
129131
addStatValueType "glean.db.write.succeeded" (writeSize `div` k) Sum
132+
case result of
133+
Left exc | writeFailureIrrecoverable ->
134+
void $ atomically $ Catalog.modifyMeta (envCatalog env) repo $ \meta ->
135+
return meta {
136+
Thrift.metaCompleteness = Thrift.Broken
137+
(Thrift.DatabaseBroken "write" (Text.pack (show exc)))
138+
}
139+
_ -> return ()
130140
immediately $ do
131141
now $ writeTVar writeQueueLatency latency
132142
now $ modifyTVar' writeQueueActive (subtract 1)
@@ -220,9 +230,11 @@ enqueueWrite
220230
-> Int
221231
-> Maybe SchemaId
222232
-> Bool
233+
-> Bool
223234
-> IO WriteContent
224235
-> IO (MVar (Either SomeException Subst.Subst))
225-
enqueueWrite env@Env{..} repo size optSchemaId checkQueueSize writeContent = do
236+
enqueueWrite env@Env{..} repo size optSchemaId checkQueueSize remember
237+
writeContent = do
226238
start <- beginTick 1
227239
config <- Observed.get envServerConfig
228240
mvar <- newEmptyMVar
@@ -251,7 +263,8 @@ enqueueWrite env@Env{..} repo size optSchemaId checkQueueSize writeContent = do
251263
{ writeSize = size
252264
, writeContentIO = writeContent
253265
, writeDone = mvar
254-
, writeStart = start }
266+
, writeStart = start
267+
, writeFailureIrrecoverable = not remember }
255268
queueCount <- now $ updateTVar writeQueueCount (+1)
256269
queueSize <- now $ updateTVar writeQueueSize (+ size)
257270
later $ do
@@ -315,7 +328,8 @@ enqueueBatch env ComputedBatch{..} ownership = do
315328

316329
let size = batchSize computedBatch_batch
317330
optSchemaId = batch_schema_id computedBatch_batch
318-
r <- try $ enqueueWrite env computedBatch_repo size optSchemaId True $ pure $
331+
r <- try $ enqueueWrite env computedBatch_repo size optSchemaId
332+
True computedBatch_remember $ pure $
319333
(writeContentFromBatch computedBatch_batch) {
320334
writeOwnership= ownership
321335
}
@@ -360,13 +374,14 @@ enqueueJsonBatch env repo batch = do
360374
maybe 0 ByteString.length jsonFactBatch_unit
361375
size = sum (map jsonFactBatchSize (sendJsonBatch_batches batch))
362376
traceMsg (envTracer env) (GleanTraceEnqueue repo EnqueueJsonBatch size) $ do
363-
handle <- UUID.toText <$> UUID.nextRandom
364-
let optSchemaId =
365-
sendJsonBatch_options batch >>= sendJsonBatchOptions_schema_id
366-
write <- enqueueWrite env repo size optSchemaId True $
367-
writeJsonBatch env repo batch
368-
when (sendJsonBatch_remember batch) $ rememberWrite env handle write
369-
return $ def { sendJsonBatchResponse_handle = handle }
377+
handle <- UUID.toText <$> UUID.nextRandom
378+
let optSchemaId =
379+
sendJsonBatch_options batch >>= sendJsonBatchOptions_schema_id
380+
remember = sendJsonBatch_remember batch
381+
write <- enqueueWrite env repo size optSchemaId True remember $
382+
writeJsonBatch env repo batch
383+
when remember $ rememberWrite env handle write
384+
return $ def { sendJsonBatchResponse_handle = handle }
370385

371386
enqueueBatchDescriptor
372387
:: Env
@@ -377,15 +392,15 @@ enqueueBatchDescriptor
377392
enqueueBatchDescriptor env repo enqueueBatch waitPolicy = do
378393
traceMsg (envTracer env)
379394
(GleanTraceEnqueue repo EnqueueBatchDescriptor 0) $ do
380-
handle <- UUID.toText <$> UUID.nextRandom
381-
descriptor <- case enqueueBatch of
382-
Thrift.EnqueueBatch_descriptor descriptor -> return descriptor
383-
Thrift.EnqueueBatch_EMPTY -> throwIO $ Thrift.Exception "empty batch"
384-
write <- enqueueWrite env repo 0 Nothing False $
385-
writeContentFromBatch <$> downloadBatchFromLocation env descriptor
386-
when (waitPolicy == Thrift.EnqueueBatchWaitPolicy_Remember)
387-
$ rememberWrite env handle write
388-
return $ def { enqueueBatchResponse_handle = handle }
395+
handle <- UUID.toText <$> UUID.nextRandom
396+
descriptor <- case enqueueBatch of
397+
Thrift.EnqueueBatch_descriptor descriptor -> return descriptor
398+
Thrift.EnqueueBatch_EMPTY -> throwIO $ Thrift.Exception "empty batch"
399+
let remember = waitPolicy == Thrift.EnqueueBatchWaitPolicy_Remember
400+
write <- enqueueWrite env repo 0 Nothing False remember $
401+
writeContentFromBatch <$> downloadBatchFromLocation env descriptor
402+
when remember $ rememberWrite env handle write
403+
return $ def { enqueueBatchResponse_handle = handle }
389404

390405
pollBatch :: Env -> Handle -> IO FinishResponse
391406
pollBatch env@Env{..} handle = do

0 commit comments

Comments
 (0)