2012-01-29 9 views
32

समवर्ती रूप से उपयोग करने के नियम क्या हैं, ऐसा लगता है कि समवर्ती पहुंच के बारे में नियम अनियंत्रित हैं (हास्केल पक्ष पर) और बस मान लें कि डेवलपर उपयोग किए जाने वाले विशेष बैकएंड से परिचित है। उत्पादन की जरूरतों के लिए यह एक पूरी तरह से वैध धारणा है, लेकिन आकस्मिक प्रोटोटाइप और विकास के लिए यह अच्छा होगा अगर लगातार- * पैकेज थोड़ा अधिक आत्मनिर्भर थे।एक सतत डेटाबेस

तो, निरंतर-स्क्लाइट और परिवार के समवर्ती उपयोग को नियंत्रित करने वाले नियम क्या हैं? जाहिर है, अगर हमारे पास कनेक्शन के पूल हैं, लेकिन कुछ कनेक्शन की पूल बनाने और replicateM x $ forkIO (useThePool connectionPool) को कॉल करने से नीचे की त्रुटि मिलती है तो कुछ डिग्री की सहमति होनी चाहिए।

user error (SQLite3 returned ErrorBusy while attempting to perform step.) 

संपादित करें: कुछ उदाहरण कोड अब नीचे है।

नीचे दिए गए कोड में मैंने 6 धागे को बंद कर दिया (एक मनमाना संख्या - मेरा वास्तविक अनुप्रयोग 3 धागे करता है)। प्रत्येक थ्रेड लगातार स्टोर करता है और एक रिकॉर्ड देखता है (किसी अन्य थ्रेड द्वारा एक्सेस किया जा रहा एक अनूठा रिकॉर्ड, लेकिन इससे कोई फर्क नहीं पड़ता), खेतों में से एक को प्रिंट करना।

{-# LANGUAGE TemplateHaskell, QuasiQuotes 
      , TypeFamilies, FlexibleContexts, GADTs 
      , OverloadedStrings #-} 
import Control.Concurrent (forkIO, threadDelay) 
import Database.Persist 
import Database.Persist.Sqlite hiding (get) 
import Database.Persist.TH 
import Control.Monad 
import Control.Monad.IO.Class 

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persist| 
SomeData 
    myId Int 
    myData Double 
    MyId myId 
|] 

main = withSqlitePool "TEST" 40 $ \pool -> do 
    runSqlPool (runMigration migrateAll) pool 
    mapM_ forkIO [runSqlPool (dbThread i) pool | i <- [0..5]] 
    threadDelay maxBound 

dbThread :: Int -> SqlPersist IO() 
dbThread i = forever $ do 
    x <- getBy (MyId i) 
    insert (SomeData i (fromIntegral i)) 
    liftIO (print x) 
    liftIO (threadDelay 100000) -- Just to calm down the CPU, 
           -- not needed for demonstrating 
           -- the problem 

नायब 40, TEST के मूल्यों, और सभी रिकॉर्ड इस उदाहरण के लिए मनमाने ढंग से कर रहे हैं। अधिक मूल्यवान लोगों सहित कई मूल्य, वही व्यवहार करते हैं।

भी ध्यान रखें कि, जबकि यह स्पष्ट रूप से तोड़ा जा सकता है जब आप एक डीबी लेन-देन (runSqlPool द्वारा शुरू) के अंदर घोंसला एक गैर समाप्त कार्रवाई (forever के माध्यम से), यह मुख्य मुद्दा नहीं है। आप उन परिचालनों को उलटा कर सकते हैं और लेन-देन को मनमाने ढंग से छोटा कर सकते हैं लेकिन फिर भी आवधिक अपवादों के साथ समाप्त हो जाते हैं।

उत्पादन आमतौर पर है की तरह है:

$ ./so 
Nothing 
so: user error (SQLite3 returned ErrorBusy while attempting to perform step.) 
so: user error (SQLite3 returned ErrorBusy while attempting to perform step.) 
so: user error (SQLite3 returned ErrorBusy while attempting to perform step.) 
so: user error (SQLite3 returned ErrorBusy while attempting to perform step.) 
so: user error (SQLite3 returned ErrorBusy while attempting to perform step.) 
so: user error (SQLite3 returned ErrorConstraint while attempting to perform step.) 
+0

क्या आप 'useThePool' के बारे में अधिक जानकारी दे सकते हैं? –

+0

@ डैनबर्टन मैंने एक संपादन के माध्यम से अधिक जानकारी दी है। अब उदाहरण कोड के साथ जो शायद उन लोगों के लिए अंधेरा रूप से गलत है जो लगातार के बारे में कुछ भी जानते हैं। –

+0

@ थॉमसएम। डूबुइसन, क्या आपने डालने के बजाय चयन का उपयोग करने का प्रयास किया है, और देखें कि क्या आप त्रुटि को पुन: उत्पन्न कर सकते हैं? अगर त्रुटि चयन पर नहीं होती है, तो त्रुटि कहीं भी फेंक दिया गया डेडलॉक रोकथाम अपवाद हो सकता है, खासकर यदि आप समवर्ती आवेषण करने की कोशिश कर रहे हैं। अगर आपके पास धागा पूल है तो समझ में नहीं आता है। – Sal

उत्तर

16

कुछ ध्यान देने योग्य है कि SQLite जब एनएफएस की तरह संस्करणों (vboxsf, एनएफएस, एसएमबी, mvfs, आदि) कई सिस्टम पर पर संग्रहीत ताला लगा के साथ मुद्दों है जो डेटाबेस को सफलतापूर्वक खोले जाने से पहले SQLite को उस त्रुटि को देने का कारण बनता है। ये वॉल्यूम fcntl() को गलत तरीके से पढ़ने/लिखने के लिए लागू कर सकते हैं। (http://www.sqlite.org/faq.html#q5)

मुद्दा है यह मानते हुए कि नहीं, यह भी उल्लेख है कि SQLite वास्तव में मूल रूप से समवर्ती "कनेक्शन" का समर्थन नहीं करता लायक है (http://www.sqlite.org/faq.html#q6) के रूप में यह फाइल सिस्टम ताले का उपयोग करता है यह सुनिश्चित करें कि दो राईट ही में नहीं होती है पहर। (http://www.sqlite.org/lockingv3.html के सेक्शन 3.0 देखें)

मान लीजिए कि यह सब ज्ञात है, आप यह भी देख सकते हैं कि आपके पर्यावरण के लिए एसक्लाइट 3 का कौन सा संस्करण उपलब्ध है, क्योंकि जिस तरह से विभिन्न प्रकार के ताले हासिल किए जाते हैं, उसमें कुछ बदलाव हुए हैं। 3.x श्रृंखला: http://www.sqlite.org/sharedcache.html

संपादित करें: जारी रहती है-sqlite3 पुस्तकालय से कुछ अतिरिक्त जानकारी के This package includes a thin sqlite3 wrapper based on the direct-sqlite package, as well as the entire C library

'पतला' आवरण मुझे इसे पर एक नज़र लेने के लिए देखने के लिए यह सिर्फ कैसे पतली है तय किए गए; कोड को देखते हुए ऐसा नहीं लगता है कि लगातार रैपर के पास पूल में एक बयान के खिलाफ कोई गार्ड है जो त्रुटि को अनुवाद/निकालने और निष्पादन को बाधित करने के लिए आवश्यक गार्ड को छोड़कर विफल रहता है, हालांकि मुझे उस चेतावनी को अवश्य प्रदान करना चाहिए जिसमें मैं सहज नहीं हूं हास्केल।

ऐसा प्रतीत होता है कि आपको पूल में विफलता और पुन: प्रयास करने के लिए एक कथन के खिलाफ सुरक्षा करना होगा, या आप पूल आकार को प्रारंभिक रूप से 1 तक सीमित कर सकते हैं (जो आदर्श से कम लगता है।)

संबंधित मुद्दे