<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ##SQLite入門與分析(六)---再談SQLite的鎖 寫在前面:SQLite封鎖機制的實現需要底層文件系統的支持,不管是Linux,還是Windows,都提供了文件鎖的機制,而這為SQLite提供了強大的支持。本節就來談談SQLite使用到的文件鎖——主要基于Linux和Windows平臺。 ##Linux的文件鎖 Linux 支持的文件鎖技術主要包括建議鎖(advisory lock)和強制鎖(mandatory lock)這兩種。此外,Linux 中還引入了兩種強制鎖的變種形式:共享模式強制鎖(share-mode mandatory lock)和租借鎖(lease)。在這里,主要討論建議鎖(advisory lock)。 建議鎖并不由內核強制實行,也就是說如果有進程不遵守“游戲規則”,不檢查目標文件是否已經由別的進程加了鎖就往其中寫入數據,那么內核是不會加以阻攔的。因此,建議鎖并不能阻止進程對文件的訪問,而只能依靠各個進程在訪問文件之前檢查該文件是否已經被其他進程加鎖來實現并發控制。進程需要事先對鎖的狀態做一個約定,并根據鎖的當前狀態和相互關系來確定其他進程是否能對文件執行指定的操作。而強制鎖是由內核強制采用的文件鎖——由于內核對每個read()和write()操作都會檢查相應的鎖,所以會降低系統性能。 對于建議鎖,Linux提供兩種實現方式:鎖文件(lock files)和記錄鎖( record locking)。 ###(1)鎖文件(lock files) 鎖文件是最簡單的對文件加鎖的方法,每個需要加鎖的數據文件都有一個鎖文件(lock file)。當鎖文件存在時,就認為該數據文件已經被加鎖,別的進程不應該訪問(但是你非要訪問,Linux也不會阻止)。當鎖不存在,進程就可以創建一個鎖文件,然后訪問相應的數據文件。只要創建鎖的過程是原子的,就能保證某一時刻只有一個進程擁有該鎖,這種方法保證某一時刻只有一個進程訪問文件。 這種想法很簡單,當一個進程想訪問文件時,可以按如下方式對文件加鎖: ~~~ fd = open("somefile.lck", O_RDONLY, 0644); if (fd >= 0) { close(fd); printf("the file is already locked"); return 1; } else { /* the lock file does not exist, we can lock it and access it */ fd = open("somefile.lck", O_CREAT | O_WRONLY, 0644"); if (fd < 0) { perror("error creating lock file"); return 1; } /* we could write our pid to the file */ close(fd); } ~~~ 當一個進程處理完文件后,就可以調用unlink("somefile.lck")釋放鎖了——本質上是刪除somefile.lck文件。 上面這段代碼實際上存在競爭情況,原因在于if語句塊不是原子性的,進入if語句塊,內核可能調度別的進程運行。更好的方式如下: ~~~ fd = open("somefile.lck", O_WRONLY | O_CREAT | O_EXCL, 0644); if (fd < 0 && errno == EEXIST) { printf("the file is already locked"); return 1; } else if (fd < 0) { perror("unexpected error checking lock"); return 1; } /* we could write our pid to the file */ close(fd); ~~~ O_EXCL標志保證open()創建鎖文件的過程是原子性的。 注意以下幾點: 1、任何時刻只有一個進程可以擁有鎖。 2、O_EXCL標志只對本志文件系統是可靠的,對于網絡文件系統并不能很好的支持。 3、鎖僅僅只是建議性的。 4、如果一個持有鎖的進程不正常結束,鎖文件仍然存在。如果加鎖進程的pid存儲在鎖文件中,其它進程可以檢查鎖進程是否存在,當它結束時就可以刪除鎖。但是,在檢查的時候,如果pid被其它進程使用了,此時就無能為力了。 ###(2)記錄鎖(Record Locking) 為了克服鎖文件的缺點,System V和BSD4.3引入了記錄鎖,相應的系統調用為lockf()和flock()。而POSIX對于記錄鎖提供了另外一種機制,其系統調用為fcntl()。Linux提供三種接口,在這里僅討論POSIX的接口。 記錄鎖和鎖文件有兩個很重要的區別:首先,記錄鎖可以對文件的任何一部分加鎖——這對于DBMS這樣的應用程序,有極大的幫助,SQLite當然沒有放過這樣的好處。其次,記錄鎖的另一個優點就是它由內核持有,而不是文件系統持有。當進程結束時,所有的鎖也隨之釋放。 和鎖文件一樣,POSIX鎖也是建議性的。記錄鎖有兩種鎖:讀鎖(read locks)和寫鎖(write locks)。讀鎖也就是共享鎖(shared lock),寫鎖也就是排它鎖(exclusive lock)。對于一個記錄,只能有一個進程持有寫鎖,讀鎖不能存在。 對于一個進程本身而言,多個鎖絕不會沖突。如果一個進程對文件的200-250字節持有讀鎖,然后對200-225字節數據加寫鎖,是會成功的。此時,200-225為寫鎖,而226-250字節數據為讀鎖,該規則主要是防止進程本身發生死鎖(盡管多進程之間仍然可能發生死鎖)。 POSIX鎖通過fcntl()系統來實現,如下: ~~~ #include <fcntl.h> int fcntl(int fd, int command, long arg); arg為指向flock結構體的指針: #include <fcntl.h> struct flock { short l_type; short l_whence; off_t l_start; off_t l_len; pid_t l_pid; }; ~~~ 在 flock 結構中,l_type 用來指明創建的是共享鎖還是排他鎖,其取值有三種:F_RDLCK(共享鎖)、F_WRLCK(排他鎖)和F_UNLCK(刪除之前建立的鎖);l_pid 指明了該鎖的擁有者;l_whence、l_start 和l_end 這些字段指明了進程需要對文件的哪個區域進行加鎖,這個區域是一個連續的字節集合。因此,進程可以對同一個文件的不同部分加不同的鎖。l_whence 必須是 SEEK_SET、SEEK_CUR 或 SEEK_END 這幾個值中的一個,它們分別對應著文件頭、當前位置和文件尾。l_whence 定義了相對于 l_start 的偏移量,l_start 是從文件開始計算的。 可以執行的操作包括: * F_GETLK:進程可以通過它來獲取通過 fd 打開的那個文件的加鎖信息。執行該操作時,lock 指向的結構中就保存了希望對文件加的鎖(或者說要查詢的鎖)。如果確實存在這樣一把鎖,它阻止 lock 指向的 flock 結構所給出的鎖描述符,則把現存的鎖的信息寫到 lock 指向的 flock 結構中,并將該鎖擁有者的 PID 寫入 l_pid 字段中,然后返回;否則,就將 lock 指向的 flock 結構中的 l_type 設置為 F_UNLCK,并保持 flock 結構中其他信息不變返回,而不會對該文件真正加鎖。 * F_SETLK:進程用它來對文件的某個區域進行加鎖(l_type的值為 F_RDLCK 或 F_WRLCK)或者刪除鎖(l_type 的值為F_UNLCK),如果有其他鎖阻止該鎖被建立,那么 fcntl() 就出錯返回 * F_SETLKW:與 F_SETLK 類似,唯一不同的是,如果有其他鎖阻止該鎖被建立,則調用進程進入睡眠狀態,等待該鎖釋放。一旦這個調用開始了等待,就只有在能夠進行加鎖或者收到信號時才會返回 需要注意的是,F_GETLK 用于測試是否可以加鎖,在 F_GETLK 測試可以加鎖之后,F_SETLK 和 F_SETLKW 就會企圖建立一把鎖,但是這兩者之間并不是一個原子操作,也就是說,在 F_SETLK 或者 F_SETLKW 還沒有成功加鎖之前,另外一個進程就有可能已經插進來加上了一把鎖。而且,F_SETLKW 有可能導致程序長時間睡眠。還有,程序對某個文件擁有的各種鎖會在相應的文件描述符被關閉時自動清除,程序運行結束后,其所加的各種鎖也會自動清除。 ### Windows中的文件鎖 Windows中的鎖都是強制鎖(mandatory locks),Windows中的共享文件通過以下幾個機制來管理: (1) 通過共享訪問控制方式,應用程序可以指定整個文件進行共享讀,寫或者刪除。 (2) 通過字節范圍鎖(byte range locks)可以對文件的某一部分進行讀寫訪問。 (3) Windows文件系統不允許正在執行的文件被打開用來進行寫或刪除操作。 文件的共享方式由WIN32 API中的打開文件函數CreateFile()中的sharing mode參數確定: HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ); dwShareMode的取值通常為: FILE_SHARE_DELETE:   Enables subsequent open operations on an object to request delete access. Otherwise, other processes cannot open the object if they request delete access. If this flag is not specified, but the object has been opened for delete access, the function fails. FILE_SHARE_READ:   Enables subsequent open operations on an object to request read access. Otherwise, other processes cannot open the object if they request read access. If this flag is not specified, but the object has been opened for read access, the function fails. FILE_SHARE_WRITE: Enables subsequent open operations on an object to request write access. Otherwise, other processes cannot open the object if they request write access. If this flag is not specified, but the object has been opened for write access, the function fails. 具體的實現函數: BOOL LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh ); SQLite封鎖機制的幾個注意點 SQLite的lock byte的定義如下: ~~~ #define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */ #define RESERVED_BYTE (PENDING_BYTE+1) #define SHARED_FIRST (PENDING_BYTE+2) #define SHARED_SIZE 510 ~~~ (1)PENDING_BYTE為何設置為0X4000 0000(1GB) 在Windows文件中,被加鎖的區域不要求有數據,并且它會阻止所有的進程寫文件的該區域,包括第一個持有該鎖的進程.為了防止出現由于對含有mandatory lock的頁面進行讀寫操作而出現錯誤(這在Windows中是不允許的),SQLite完全忽略包含pending byte的頁面,所以pending byte在數據庫文件上產生一個”文件洞”。PENDING_BYTE設置得那么高,則大部分數據庫文件不會遇到由于PENDING_BYTE產生”文件洞”引起的空間損失(除非文件特別大,超過1GB)。 (2)對于Windows來說,文件中加鎖的區域不能重疊,為了使兩個讀進程可以同時訪問文件,對于SHARED LOCK選擇一個SHARED_FIRST——SHARED_FIRST+ SHARED_SIZE范圍內的隨機數,所以有可能兩個進程取得一樣的lock byte,所以對于Windows,SQLite的并發性就受到限制。 分類: 數據庫技術
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看