인 메모리 인덱스에 대한 우수한 스냅 샷 가능 데이터 구조


12

매우 구체적인 사용 사례를 위해 메모리 내 객체 데이터베이스를 설계하고 있습니다. 단일 작성자이지만 효율적인 동시 읽기를 지원해야합니다. 판독 값은 분리해야합니다. 쿼리 언어가 없으며 데이터베이스는 다음을 지원합니다.

  • 속성 / 속성 집합별로 객체를 가져옵니다 (예 : 식을 지원할 수 있음 x.count < 5)
  • 객체의 속성을 얻는다

쿼리는 위의 여러 작업으로 구성된 명령형 스크립트입니다. 데이터 크기는 << 메모리이므로 대부분의 속성에있는 모든 객체와 인덱스는 스와핑하지 않고 편안하게 맞아야합니다.

필요한 것은 쓰기의 O (n) 일 수 있으며 쓰기 동시성을 지원하지 않지만 이상적으로 O (1) 스냅 샷 (쓰기시 복사 가능) 및 O (logN) 액세스를 지원 해야하는 객체의 속성 색인에 대한 데이터 구조입니다. 이상적으로는 버전간에 최대한의 구조적 공유를 통해 읽기에서 높은 동시성을 허용합니다.

나는보고 있었다 CTries , 동시 BST를 하고 동시 스플레이 나무 하지만 난 정말 여기에 올바른 방향으로 찾고 있는지 확실하지 않습니다. 위의 구조는 내가 신경 쓰지 않는 인서트의 복잡성에 많은 관심을 기울입니다.

질문 : 사용 사례에 적합한 알려진 데이터 구조가 있습니까?

편집 : 좀 더 생각하면 지속적인 BST / Splay 트리가 작동하는 것 같습니다. 라이터는 '마스터'복사본을 업데이트하고 쿼리는 실행 시작시 트리를 가져 와서 완료된 후에 버립니다. 그러나 더 나은 솔루션이 있는지 여전히 관심이 있습니다.


1
메모리에 스냅 샷이 필요합니까? 아니면 디스크 / 네트워크에 저장해야합니까? 순전히 기능적인 데이터 구조는 자동으로 인 메모리 스냅 샷을 제공하므로 필요한 경우 최상의 선택입니다.
Gilles 'SO- 악마 그만해'

모든 것이 기억에 있습니다. 일정 시간 스냅 샷 (CTrie와 같은 동시 쓰기가없는)을 가진 효율적인 가변 버전이 있는지 궁금합니다.
dm3

2
문제는 데이터 구조의 선택이 아니라 동시성 제어의 종류 일 수 있습니다.
라파엘

아마도 좀 더 자세히 설명해 주시겠습니까?
dm3

답변:


5

모든 종류의 영구적 / 불변 (즉, 기능적) 트리 기반 데이터 구조를 사용하십시오. @Raphael이 주석에서 지적했듯이 핵심은 잠금 권한을 얻는 것입니다.

기능적 / 지속적 트리 기반 데이터 구조의 장점은 무료로 "스냅 샷"을 얻는 것입니다. 데이터 구조에 treap (무작위 이진 검색 트리)을 사용한다고 가정 해 봅시다 . : 여기에 기록 된 하나의 예 https://github.com/steveyen/gtreap . 저자는 다음과 같이 설명합니다.

변경 불가능한 경우, treap에 대한 모든 업데이트 / 삭제는 이전 treap과 내부 노드를 공유 할 수있는 새로운 treap을 반환합니다. 이 구현의 모든 노드는 생성 후 읽기 전용입니다. 따라서 수정은 새로운 데이터 구조 만 작성하고 기존 데이터 구조는 수정하지 않으므로 동시 판독기는 동시 작성기와 안전하게 작동 할 수 있습니다. 이것은 MVCC 또는 다중 버전 동시성 제어를 달성하는 간단한 방법입니다.

O(logn)

잠금을 사용하여 루트에 대한 포인터를 보호하십시오. 데이터 구조는 불변이므로 읽기를 동시에 수행 할 수 있으며 이전 스냅 샷에 대한 포인터를 저장할 수 있습니다. 읽은 내용은 다음과 같습니다.

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

검색하는 데 시간이 걸릴 수 있지만 포인터를 복사하는 동안 잠금 만 잡고 있으면 동시에 검색 할 수 있습니다.

글은 :

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

이 버전에서는 새 버전의 트리를 작성하는 전체 프로세스 중에 쓰기 작업에서 잠금을 유지해야합니다. 쓰기를 다음과 같이 변경하여 읽기 성능을 향상시킬 수 있습니다 (쓰기 트랜잭션이 실패하는 경우가 있음).

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

프로그래밍 언어에 원자 비교 및 ​​스왑 작업이있는 원자 변수가있는 경우 약간 더 잘 수행 할 수 있습니다 ( "자유 잠금"으로 설정). (예를 들어 C ++ 11을 사용하여 atomic<T*>)


정교한 답변에 감사드립니다. 나는 그 질문 자체에 충분히 명확하게 설명하지 않았을 수도 있다는 것을 알았습니다. 그러나 답은 여전히 ​​큽니다!
dm3

"개선 된"버전은 사용중인 시스템의 메모리 모델에 따라 다릅니다. 일부 시스템에서는 휘발성으로 선언 할 수있는 verables가 필요할 수 있으며 코딩을 올바르게하려면 뛰어난 기술이 필요합니다.
이안 링 로즈

1

Microsoft는 새로운 메모리 데이터베이스에 대한 세부 정보를 게시했으며 쓰기가 수행되는 동안 읽기를 차단하지 않는 인덱스를 가지고 있습니다.

예를 들면 다음과 같습니다.

Justin Levandoski, David Lomet 및 Sudipta Sengupta, Bw-Tree : 새로운 하드웨어의 B- 트리, 2013 년 IEEE 29 번째 ICD (International Conference of Data Engineering), 2013 년 4 월 8 일 국제 데이터 공학 회의.

출판물 목록은 http://research.microsoft.com/en-us/projects/main-memory_dbs/ 를 참조하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.