Cấu trúc dữ liệu snapshottable tốt cho chỉ mục trong bộ nhớ


12

Tôi đang thiết kế một cơ sở dữ liệu đối tượng trong bộ nhớ cho trường hợp sử dụng rất cụ thể. Nó là nhà văn duy nhất, nhưng phải hỗ trợ đọc đồng thời hiệu quả. Đọc phải được cách ly. Không có ngôn ngữ truy vấn, cơ sở dữ liệu chỉ hỗ trợ:

  • lấy đối tượng / -s theo thuộc tính / bộ thuộc tính (có thể có hỗ trợ cho biểu thức, ví dụ x.count < 5)
  • lấy thuộc tính của đối tượng

Một truy vấn là một tập lệnh bắt buộc bao gồm một số lượng tùy ý của các hoạt động trên. Kích thước dữ liệu sẽ là << bộ nhớ, vì vậy tất cả các đối tượng và chỉ mục trên hầu hết các thuộc tính phải vừa vặn thoải mái mà không cần trao đổi.

Cái tôi cần là một cấu trúc dữ liệu cho chỉ mục thuộc tính của đối tượng, có thể là O (n) khi ghi, không hỗ trợ ghi đồng thời, nhưng nên hỗ trợ các ảnh chụp nhanh O (1) lý tưởng (có thể sao chép trên ghi) và truy cập O (logN). Lý tưởng nhất là nó sẽ cho phép đọc đồng thời cao với việc chia sẻ cấu trúc tối đa giữa các phiên bản.

Tôi đã xem xét CTries , BST đồng thờiCây Splay đồng thời nhưng tôi không chắc liệu tôi có thực sự nhìn đúng hướng ở đây không. Các cấu trúc trên chú ý rất nhiều đến sự phức tạp của các hạt dao mà tôi không quan tâm.

Câu hỏi : có cấu trúc dữ liệu đã biết nào phù hợp với trường hợp sử dụng của tôi không?

EDIT : sau khi suy nghĩ thêm, có vẻ như một cây BST / Splay bền bỉ sẽ hoạt động. Người viết sẽ cập nhật bản sao của 'chủ nhân' và các truy vấn sẽ lấy cây khi bắt đầu thực hiện và vứt nó đi sau khi chúng được thực hiện. Tuy nhiên, tôi vẫn quan tâm nếu có một giải pháp tốt hơn.


1
Bạn có cần ảnh chụp nhanh trong bộ nhớ, hoặc bạn cần lưu chúng vào đĩa / mạng? Cấu trúc dữ liệu hoàn toàn có chức năng tự động cung cấp cho bạn ảnh chụp nhanh trong bộ nhớ, vì vậy nếu đó là thứ bạn cần, thì đó là cách tốt nhất của bạn.
Gilles 'SO- ngừng trở nên xấu xa'

Đó là tất cả trong bộ nhớ. Tôi đã tự hỏi có lẽ có một phiên bản có thể thay đổi hiệu quả với ảnh chụp nhanh liên tục (như CTrie, chỉ khi không có ghi đồng thời).
dm3

2
Vấn đề của bạn có thể là sự lựa chọn ít hơn về cấu trúc dữ liệu, nhưng là loại kiểm soát tương tranh.
Raphael

Nó cũng có thể, bạn có thể giải thích thêm một chút nữa không?
dm3

Câu trả lời:


5

Sử dụng bất kỳ loại cấu trúc dữ liệu dựa trên cây liên tục / bất biến (nghĩa là chức năng). Điều quan trọng là khóa đúng, như @Raphael đã chỉ ra trong các bình luận.

Điều thú vị về cấu trúc dữ liệu dựa trên cây có chức năng / liên tục là bạn có được "ảnh chụp nhanh" miễn phí. Giả sử bạn sử dụng một treap (cây tìm kiếm nhị phân ngẫu nhiên) cho cấu trúc dữ liệu của bạn. Đây là một ví dụ về một bài được viết bằng Go: https://github.com/steveyen/gtreap . Tác giả mô tả nó như vậy:

Bằng cách không thay đổi, bất kỳ cập nhật / xóa nào cho một treap sẽ trả về một treap mới có thể chia sẻ các nút nội bộ với treap trước đó. Tất cả các nút trong triển khai này là chỉ đọc sau khi tạo. Điều này cho phép người đọc đồng thời hoạt động an toàn với người viết đồng thời vì sửa đổi chỉ tạo cấu trúc dữ liệu mới và không bao giờ sửa đổi cấu trúc dữ liệu hiện có. Đây là một cách tiếp cận đơn giản để đạt được MVCC hoặc kiểm soát đồng thời nhiều phiên bản.

Ôi(đăng nhậpn)

Bạn sử dụng một khóa để bảo vệ con trỏ đến thư mục gốc. Vì cấu trúc dữ liệu là các lần đọc bất biến có thể được thực hiện đồng thời và bạn có thể lưu các con trỏ vào các ảnh chụp nhanh cũ. Một đọc là:

lock
tmp = ptr_to_root
unlock
value = search(tmp, <value to search for>)
return value

Mặc dù tìm kiếm có thể mất một lúc, bạn chỉ giữ khóa trong khi sao chép con trỏ, vì vậy các tìm kiếm có thể xảy ra đồng thời.

Viết là:

lock
old_ptr_to_root = ptr_to_root
ptr_to_root = insert(old_ptr_to_root, <new key/value pair>)
unlock

Trong phiên bản này, write cần phải giữ khóa trong toàn bộ quá trình tạo phiên bản mới của cây. Bạn có thể cải thiện hiệu suất đọc (với chi phí đôi khi có giao dịch ghi bị lỗi) bằng cách thay đổi ghi thành một cái gì đó như thế này:

top:
  lock
  old_ptr_to_root = ptr_to_root
  unlock
  new_ptr_to_root = insert(old_ptr_to_root, <new key/value pair>)
  lock
  if (ptr_to_root == old_ptr_to_root)   # make sure no other write happened in the interim
    ptr_to_root = new_ptr_to_root
    unlock
  else                                  # transaction fails, try again
    unlock
    goto top

Bạn có thể làm tốt hơn một chút (làm cho nó "khóa miễn phí") nếu ngôn ngữ lập trình của bạn có các biến nguyên tử với hoạt động so sánh và trao đổi nguyên tử. (Ví dụ: bằng cách sử dụng C ++ 11. atomic<T*>)


Cảm ơn câu trả lời công phu. Tôi biết rằng, có lẽ tôi đã không đặt điều đó đủ rõ ràng vào chính câu hỏi. Tuy nhiên, câu trả lời vẫn rất tuyệt!
dm3

Phiên bản "cải tiến" của bạn phụ thuộc vào kiểu bộ nhớ của hệ thống đang sử dụng. Nó cũng có thể cần xác minh để được tuyên bố không ổn định trên một số hệ thống và cần kỹ năng tuyệt vời để có được mã hóa chính xác.
Ian Ringrose

1

Microsoft đã công bố chi tiết về cơ sở dữ liệu bộ nhớ mới của họ, nó có các chỉ mục không chặn đọc trong khi ghi đang được thực hiện.

Ví dụ:

Justin Levandoski, David Lomet, và Sudipta Sengupta, The Bw-Tree: Cây B cho phần cứng mới, năm 2013 Hội nghị quốc tế về kỹ thuật dữ liệu (29) của IEEE, Hội nghị quốc tế về kỹ thuật dữ liệu, ngày 8 tháng 4 năm 2013.

Xem http://research.microsoft.com/en-us/projects/main-memory_dbs/ để biết danh sách các ấn phẩm của họ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.