Bảng khoá hệ thống và bảng các loại khóa

Một phần của tài liệu Quản lý giao tác trong CSDL quan hệ và phân tán (Trang 47)

Có một số loại khóa được sử dụng trong điều khiển đồng thời. Đầu tiên là các khóa nhị phân (Binary locks), khóa nhị phận đơn giản nhưng có hạn chế và do vậy không được sử dụng trong thực tế. Sau đó là các khóa Shared/Exclusive, nó đưa ra các khả năng khoá tổng quát hơn và được sử dụng trong các lược đồ khóa cơ sở dữ liệu thực tế. Phần này trình bày các loại khóa và cách sử dụng khóa để cải thiện hiệu suất của các giao thức khóa.

Khóa nhị phân (Binary locks). Một khóa nhị phân có thể có 2 trạng thái hoặc 2 giá trị: Khóa và mở khóa (hoặc 0 và 1). Một khóa rõ ràng là được kết hợp với mỗi mục cơ sở dữ liệu X. Nếu giá trị của khóa trên X là 1 thì mục dữ liệu X không thể truy cập được bởi một hành động cơ sở dữ liệu mà nó yêu cầu mục dữ liệu đó. Nếu giá trị khóa của X là 0 thì mục dữ liệu có thể được truy cập khi được yêu cầu. Gán giá trị (hoặc trạng thái) hiện tại của khóa kết hợp với X là LOCK(X) [1].

Có 2 thao tác, lock_item unlock_item là được sử dụng với khóa nhị phân. Một giao tác yêu cầu truy cập vào mục dữ liệu X bằng cách đưa ra một thao tác đầu tiên lock_item(X). Nếu LOCK(X) = 1, giao tác buộc phải đợi. Nếu LOCK(X) = 0, giao tác được cho phép truy cập mục dữ liệu X. Khi giao

tác đã sử dụng mục dữ liệu, nó đưa ra một thao tác unlock_item(X), thiết lập LOCK(X) = 0 (mở khóa mục dữ liệu) bởi vậy X có thể được truy cập bởi các giao tác khác. Do đó, khóa nhị phân có hiệu lực loại trừ lẫn nhau trên mục dữ liệu. Hình 2.1 mô tả thao tác lock_item(X) và unlock_item(X) [1][5].

Chú ý là các thao tác lock_item và unlock_item phải được thực thi như các bộ không thể chia được (được biết như là bộ phận quyết định trong hệ điều hành); có nghĩa là, không có sự đan xen cho phép thao tác khóa và mở khóa chỉ một lần được bắt đầu cho đến khi thao tác kết thúc hoặc chờ giao tác. Trong hình 2.1, đợi lệnh trong khi thao tác lock_item(X) thường được thực thi bằng cách đặt giao tác vào hàng đợi đợi mục X cho đến khi X mở khóa và giao tác có thể được phép truy cập nó. Các giao tác khác cũng muốn truy cập X phải được đặt trong hàng đợi tương tự [1].

Lock_item(X):

B: If LOCK(X)=0 (*mục dữ liệu không khóa*) Then LOCK(X)  1 (*khóa mục dữ liệu*) Else begin

Wait (until lock(X) = 0 and bắt đầu giao tác); Go to B

End;

Unlock_item(X):

LOCK(X)  0; (*Mở khóa mục dữ liệu*)

Nếu có bất kỳ giao tác nào đợi thì thực hiện một trong các giao tác;

Rất đơn giản để thực thi một khóa nhị phân; chỉ cần một biến có giá trị nhị phân LOCK, được kết hợp với mỗi mục dữ liệu trong cơ sở dữ liệu. Dạng đơn giản nhất, mỗi khóa có thể là một bản ghi với 3 trường: <Tên mục dữ liệu,LOCK,giao tác khóa> cùng với một chuỗi các giao tác đang đợi truy cập mục dữ liệu. Hệ thống chỉ cần duy trì các bản ghi này đối với các mục dữ liệu hiện tại đã bị khóa trong một bảng khóa, bảng khóa này có thể được thiết lập như một tệp mã hóa. Các mục dữ liệu không có trong bảng khóa được xem như đã mở khóa. DBMS có một hệ thống con quản lý khóa để lưu lại dấu vết và điều khiển truy cập các khóa.

Nếu lược đồ khóa nhị phân đã mô tả ở đây được sử dụng, mọi giao tác phải tuân theo quy tắc sau [1,5]:

(1) Một giao tác T phải đưa ra thao tác lock_item(X) trước khi có bất kỳ thao tác read_item(X) hoặc write_item(X) được thực hiện trong T. (2) Một giao tác T phải đưa ra thao tác unlock_item(X) sau khi mọi thao

tác read_item(X), write_item(X) được thực hiện hoàn thành trong T. (3) Một giao tác T sẽ không đưa ra một thao tác lock_item(X) nếu nó đã

chứa khóa trên mục dữ liệu X.

(4) Một giao tác T sẽ không đưa ra một thao tác unlock_item(X) nếu nó không chứa khóa trên mục dữ liệu X.

Các quy tắc này có thể bị ảnh hưởng bởi bộ phận quản lý khóa của DBMS. Giữa hai thao tác lock_item(X) và unlock_item(X) trong giao tác T, T được gọi là chứa khóa trên mục X. Một giao tác có thể có tối đa một khóa trên một mục dữ liệu riêng biệt. Do đó không thể có 2 giao tác đồng thời truy cập vào cùng một mục dữ liệu.

Khóa Shared/Exclusion (hoặc Read/Write). Lược đồ khóa nhị phân cho ở trên là quá hạn chế đối với các mục cơ sở dữ liệu, bởi vì chỉ có tối đa một giao tác có thể giữ khóa trên một mục dữ liệu lấy ra. Với mục đích chỉ đọc thì có thể cho phép một số giao tác truy cập vào cùng một mục dữ liệu X. Tuy nhiên, nếu một giao tác là ghi vào mục dữ liệu X, nó phải là duy nhất truy cập vào X. Với mục đích này, một loại khóa khác được gọi là khóa nhiều cơ chế (multiple-mode lock) được sử dụng. Trong lược đồ này được gọi là khóa shared/exclusive hoặc là read/write [1].

(1) Shared (read): Nếu một giao tác Ti nhận được một khóa ở phương thức shared trên mục X, khi đó Ti chỉ có thể đọc nhưng không thể ghi X.

(2) Exclusive (write): Nếu một giao tác tác Ti nhận được một khóa ở phương thức exclusive trên mục X, khi đó Ti có thể cả đọc và ghi X.

Có 3 thao tác khóa: read_item(X), write_item(X) và unlock(X). Một khóa kết hợp với một mục X, LOCK(X), có 3 trạng thái có khả năng: “read- locked”, “write-locked” hoặc “unlocked”. Một mục dữ liệu là read-locked cũng được gọi là share-locked, bởi vì các giao tác khác được phép đọc mục dữ liệu, ngược lại một mục là write-locked cũng được gọi là exclusive-locked, bởi vì chỉ có một giao tác dành riêng giữ khóa trên mục dữ liệu [1,10].

Một phương pháp để thực thi ba thao tác ở trên trên một khóa

shared/exclusive là giữ lại các theo dõi số lượng các giao tác giữ khóa shared trên một mục dữ liệu trong bảng khóa. Mỗi bản ghi trong bảng khóa sẽ có 4 trường:

Như trên, để tiết kiệm bộ nhớ, hệ thống chỉ cần giữ các bản ghi khóa đối với các mục dữ liệu được khóa trong bảng khóa. Giá trị (trạng thái) của LOCK thì hoặc là read_locked hoặc là write-locked, được mã hóa phù hợp. Nếu LOCK(X) = write-locked, giá trị của locking_transaction(s) là một giao tác đơn giữ khóa exclusive (write) trên X. Nếu LOCK = read-locked, giá trị của locking_transaction(s) là một danh sách của một hay nhiều giao tác giữ khóa shared (read) trên X. Ba thao tác read_lock(X), write_lock(X) và unlock(X) được mô tả trong hình 2.2. Như trước, mỗi thao tác được coi là riêng lẻ; do không có sự đan xen nên cho phép một lần một thao tác được bắt đầu cho đến khi hoặc thao tác kết thúc hoặc giao tác được vào hàng đợi đợi mục dữ liệu.

Read_lock(X):

B: if LOCK(X) = “unlocked”

Then begin LOCK(X)  “read-locked”; No_of_reads(X)  1

End

Else if LOCK(X) = “read-locked”

Then no_of_reads(X)  no_of_reads(X) + 1 Else begin wait (until LOCK(X) = “unlocked” and

Bộ phận quản lý khóa bắt đầu thực hiện giao tác);

Go to B

End; Write_lock(X):

B: if LOCK(X) = “unlocked”

Then LOCK(X)  “write-locked”; Else begin

Bộ phận quản lý khóa bắt đầu thực hiện giao tác); Go to B

End; Unlock(X):

if LOCK(X) = “write-locked”

Then begin LOCK(X)  “unlocked”;

Thực hiện một trong các giao tác đang đợi (nếu có) end

Else if LOCK(X) = “read-locked” Then begin

no_of_reads(X)  no_of_reads(X) - 1 if no_of_reads(X) = 0

then begin LOCK(X) = “unlocked”

Thực hiện một trong các giao tác đang đợi (nếu có) end

end;

Hình 2.2 Thao tác khóa và mở khóa đối với 2 chế độ khóa shared/exclusive

Các khóa phương thức Shared có thể được giữ đồng thời trên một mục dữ liệu. Một khóa exclusive đến sau phải chờ đến tận khi tất cả các khóa phương thức Shared đến trước được giải phóng.

Một giao tác yêu cầu một khóa Shared trên mục dữ liệu X bằng cách thực hiện chỉ thị lock-Shared(X), yêu cầu một khóa Exclusive thông qua chỉ thị lock-EXCLUSIVE(X). Một mục dữ liệu X có thể được tháo khóa thông qua chỉ thị unlock(X).

Để truy cập một mục dữ liệu, giao tác Ti đầu tiên phải khóa mục này. Nếu mục này đã bị khóa bởi một giao tác khác ở phương thức không tương thích, bộ điều khiển cạnh tranh sẽ không cấp khóa cho đến tận khi tất cả các khóa không tương thích bị giữ bởi các giao tác khác được mở. Như vậy Ti phải chờ đến tận khi tất cả các khóa không tương thích bị giữ bởi các giao tác khác được giải phóng.

Giao tác Ticó thể tháo khóa một mục dữ liệu mà nó đã khóa trước đây. Một giao tác cần thiết phải giữ một khóa trên một mục dữ liệu chừng nào mà nó còn truy cập mục này. Hơn nữa, đối với một giao tác việc mở khóa ngay Sau truy cập cuối cùng đến mục dữ liệu không luôn luôn là điều mong muốn vì như vậy tính khả năng tuần tự có thể không được đảm bảo [2]. Để minh hoạ cho tình huống này, ta xét ví dụ Sau: A và B là hai tài khoản có thể được truy cập bởi các giao tác T1và T2. Giao tác T1 chuyển 50$ từ tài khoản B sang tài khoản A và được xác định như sau :

T1: Lock-EXCLUSIVE(B); Read_item(B); B:=B-50; Write_item(B); Unlock(B); Lock-EXCLUSIVE(A); Read_item(A); A:=A+50; Write_item(A); Unlock(A);

Giao tác T2 hiển thị tổng số lượng tiền trong các tài khoản A và B (A + B) và được xác định như sau;

T2: Lock-SHARED(A); Read_item(A); Unlock(A); Lock-SHARED(B); Read_item(B); Unlock(B); Display(A+B);

Giả sử giá trị của tài khoản A và B tương ứng là 100$ và 200$. Nếu hai giao tác này thực hiện tuần tự, hoặc theo thứ tự T1, T2 hoặc theo thứ tự T2, T1, và khi dó T2sẽ hiển thị giá trị 300$. Tuy nhiên nếu các giao tác này thực hiện đồng thời, giả sử theo trình tự Schedule-1, trong trường hợp như vậy giao tác T2 sẽ hiển thị giá trị 250$ --- một kết quả không đúng. Lý do của sai lầm này là do giao tác T1 đã mở khóa mục B quá sớm và T2 đã tham khảo một trạng thái không nhất quán.

Trình tự Schedule 1 bày tỏ các hành động được thực hiện bởi các giao tác cũng như các thời điểm khi các khóa được cấp bởi bộ quản trị điều khiển đồng thời. Giao tác đưa ra một yêu cầu khóa không thể thực hiện hành động kế tiếp của mình đến tận khi khóa được cấp bởi bộ quản trị điều khiển đồng thời; do đó, khóa phải được cấp trong khoảng thời gian giữa hoạt động yêu cầu khóa và hành động sau của giao tác. Sau này ta sẽ luôn giả thiết khóa được cấp cho giao tác ngay trước hành động kế và như vậy ta có thể bỏ qua cột bộ quản trị điều khiển đồng thời trong bảng

T 1 T 2 Bộ quản trị điều khiển đồng thời Lock-EXCLUSIVE(B) Grant-EXCLUSIVE(B,T 1) Read_item(B) B:=B-50 Write_item(B) Unlock(B) Lock-SHARED(A) Grant-SHARED(A,T 2) Read_item(A) Unlock(A) Lock-SHARED(B) Grant-SHARED(B,T 2) Read_item(B) Unlock(B) Display(A+B) Lock-EXCLUSIVE(A) Grant-EXCLUSIVE(A,T 1) Read_item(A) A:=A+50 Write_item(A) Unlock(A) Schedule-1

Bây giờ, giả sử rằng mở khóa bị làm trễ đến cuối giao tác. Giao tác T3 tương ứng với T1 với mở khóa bị làm trễ được định nghĩa như sau:

T3 Lock-EXCLUSIVE(B); Read_item(B); B:=B-50; Write_item(B); Lock-EXCLUSIVE(A); Read_item(A); A:=A+50; Write_item(A); Unlock(B); Unlock(A);

Giao tác T4 tương ứng với T2 với mở khóa bị làm trễ được xác định như sau: T4: Lock-SHARED(A); Read_item(A); Lock-SHARED(B); Read_item(B); Display(A+B); Unlock(A); Unlock(B);

Các trình tự có thể trên T3 và T4 không để cho T4 hiển thị trạng thái không nhất quán.

Tuy nhiên, sử dụng khóa có thể dẫn đến một tình huống không mong đợi. Ta hãy xét trình tự bộ phận Schedule-2 trên T3 và T4 sau:

T 3 T 4 Lock-EXCLUSIVE(B) Read_item(B) B:=B-50 Write_item(B) Lock-SHARED(A) Read_item(A) Lock-SHARED(B) Lock-EXCLUSIVE(A) Schedule-2

Do T3 giữ một khóa phương thức Exclusive trên B, nên yêu cầu một khóa phương thức Shared của T4 trên B phải chờ đến khi T3 mở khóa. Cũng vậy, T3 yêu cầu một khóa Exclusive trên A trong khi T4 đang giữ một khóa Shared trên nó và như vậy phải chờ. Ta gặp phải tình huống trong đó T3 chờ

đợi T4 đồng thời T4 chờ đợi T3 -- một sự chờ đợi vòng tròn -- và như vậy không giao tác nào có thể tiến triển. Tình huống này được gọi là khoá chết (deadlock). Khi tình huống khoá chết xảy ra hệ thống buộc phải cuộn lại một trong các giao tác. Mỗi khi một giao tác bị cuộn lại, các mục dữ liệu bị khóa bởi giao tác phải được mở khóa và nó trở nên sẵn có cho giao tác khác, như vậy các giao tác này có thể tiếp tục được sự thực hiện của nó.

Nếu ta không sử dụng chốt hoặc tháo chốt hạng mục dữ liệu ngay khi có thể sau đọc hoặc viết hạng mục, ta có thể rơi vào trạng thái không nhất quán. Mặt khác, nếu ta không tháo chốt một hạng mục dữ liệu trước khi yêu cầu một chốt trên một hạng mục khác, khóa chết có thể xảy ra. Có các phương pháp tránh khóa chết trong một số tình huống, tuy nhiên nói chung khóa chết là khó tránh khi sử dụng khóa nếu ta muốn tránh trạng thái không nhất quán. Khóa chết được ưa thích hơn trạng thái không nhất quán vì chúng có thể điều khiển được bằng cách cuộn lại các giao tác trong khi đó trạng thái không nhất quán có thể dẫn đến các vấn đề thực tế mà hệ CSDL không thể điều khiển [1].

Ta sẽ yêu cầu mỗi giao tác trong hệ thống tuân theo một tập các quy tắc, chỉ định khi một giao tác có thể khóa và mở khóa mỗi một trong các mục dự liệu. Giao thức khóa hạn chế số các trình tự có thể.

Khi sử dụng lược đồ khóa shared/exclusive, hệ thống phải tuân theo các quy tắc sau [1,10]:

(1) Một giao tác T phải đưa ra thao tác read_lock(X) hoặc write_lock(X) trước khi có bất kỳ thao tác read_item(X) nào trong T được thực hiện.

(2) Một giao tác T phải đưa ra thao tác write_item(X) trước khi có bất kỳ thao tác write_item(X) nào trong T được thực hiện.

(3) Một giao tác T sẽ đưa ra một thao tác unlock(X) sau khi tất tả các thao tác read_item(X) và write_item(X) trong T được thực hiện xong.

(4). Một giao tác T sẽ không đưa ra một thao tác read_lock(X) nếu nó giữ khóa shared (read) hoặc exclusive (write) trên mục dữ liệu X. (5) Một giao tác T sẽ không đưa ra một thao tác write_lock(X) nếu nó

giữ khóa shared hoặc khóa exclusive trên mục dữ liệu X.

(6) Một giao tác T sẽ không đưa ra một thao tác unlock(X) nếu nó không giữ khóa shared hoặc khóa exclusive trên mục dữ liệu X.

Chuyển đổi khóa (Conversion of locks) Việc chuyển đổi khóa cũng được mong đợi để giảm bớt các điều kiện 4 và 5 trong danh sách theo trình tự cho phép chuyển đổi khóa; có nghĩa là một giao tác giữ một khóa trên mục dữ liệu X được cho phép dưới các điều kiện đảm bảo để chuyển đổi khóa từ một trạng thái khóa sang trạng thái khác. Ví dụ, khả năng để một giao tác T đưa ra một thao tác read_lock(X) và sau đó nâng cấp khóa bằng cách đưa ra thao tác write_lock(X). Nếu T là một giao tác chỉ giữ khóa đọc trên X thì tại một thời điểm nào đó nó đưa ra thao tác write_lock(X) và khóa có thể được nâng cấp; ngược lại, giao tác phải đợi. Cũng có thể một giao tác T đưa ra một thao tác write_lock(X) sau khi hạ cấp khóa bằng cách đưa ra thao tác read_lock(X). Khi sử dụng khóa nâng cấp hoặc hạ cấp, bảng khóa phải bao gồm các nhận dạng giao tác trong cấu trúc bản ghi của mỗi khóa (trong trường locking_transaction(s)) để lưu giữ thông tin các giao tác giữ khóa trên mục dữ liệu. Mô tả các thao tác read_lock(X) và write_lock(X) trong hình 2.2 phải được thay đổi tương ứng [1].

Sử dụng khóa nhị phân hoặc khóa shared/Exclusive trong giao tác như được mô tả ở trên không đảm bảo tính khả năng tuần tự của các lịch biểu.

Hình 2.3 chỉ ra một ví dụ với các quy tắc khóa cho trước nhưng kết quả có thể là một lịch biểu không thể tuần tự. Điều này là do trong hình 2.3(a) các mục Y trong T1 và X trong T2 được mở quá sớm. Điều này kéo theo một lịch biểu chẳng hạn một lịch biểu được chỉ ra trong hình 2.3(c) xuất hiện, nó không phải là lịch biểu tuần tự do đưa ra kết quả không đúng. Để đảm bảo tính tuần tự, chúng ta phải kéo thêm một giao thức liên quan đến khả năng thao tác khóa và mở khóa trong mọi giao tác. Giao thức khóa 2 kỳ (Two - phase locking)

Một phần của tài liệu Quản lý giao tác trong CSDL quan hệ và phân tán (Trang 47)

Tải bản đầy đủ (PDF)

(96 trang)