2017-09-30 3 views
1

저는 많은 사람들이 내용을 편집 할 수있는 위키피디아를 만들려고합니다. 권한을 가진 사람들도 변경 사항을 되돌릴 수 있습니다. 나는 역전이 손실되기를 원하지 않는다. (이것은 사람들이 만든 편집을 정말로 드롭하는 것을 의미한다. 단지 숨겨야 만한다.) 그래서 이것은 데이터 구조와 같은 git 브랜치가 "현재"를 가리키는 포인터로 편집을 저장하는 것을 요구한다. relationship 기록은 새로운 기사 또는 기존 문서의 편집의 경우어떻게 postgresql에서 데이터 구조와 같은 git branch를 저장하나요?

CREATE TABLE article (
    id serial PRIMARY KEY, 
    content text NOT NULL, 
    author integer NOT NULL REFERENCES "user", 
    path text NOT NULL, 
    relationship ltree NOT NULL 
); 

CREATE TABLE current_article (
    article_id NOT NULL REFERENCES article 
); 

: 여기

id | content | path | author | relationship 
---+---------+------+--------+------------- 
1 | foo  | /a1 | 1  | 'root' 
2 | bar  | /a1 | 2  | 'root.1' 
3 | baz  | /a2 | 3  | 'root' 

, 그것은 의미는, 저자 2에서 기사 /a1을 변경

나는이 디자인을 시도 foo에서 bar까지, 그리고 /a2 문서는 새로운 것입니다.

current_article "현재"기사 인 기사를 기록하며 대개 최신 기사를 가리 킵니다. 복귀 후에는 가리킬 수 있습니다 이전 하나

article_id 
---------- 
2 
3 

편집이 들어 오면, 나는 다음과 같이 삽입 :

INSERT INTO article (content, path, author) VALUES ('qux', '/a2', 4); 

그리고 현재 기사를 찾아 삽입 트리거 전에에 의존 해당 경로 및 채우기 관계, 및 현재 기사 포인터를 업데이트하기위한 삽입 후 트리거.

이 디자인에 대해 어떻게 생각하십니까? 이 디자인에서 가지고있는 문제는 동시성을 다루는 것이 어렵다는 것입니다.

이전 삽입 트리거에서 현재 기사를 찾을 때까지 이미 변경되었을 수 있으며 삽입 후 트리거에서 이미 다른 기사를 가리키는 현재 기사를 잘못 덮어 쓸 수 있습니다.

나는이 점에서 세 가지 질문이 있습니다

  1. 가 직렬화 분리 문제를 해결할 것인가를? (나는 MVCC의 개념에 대해 아주 새로운데, 여전히 내 머리를 감싸려고 노력하고있다.) 그렇지 않다면 어떻게 해결해야 할까?
  2. 동시성을 처리 할 필요가없는 더 나은 디자인이 있습니까?
  3. 동시성을 처리해야하는 경우 어떻게 다른 경쟁 조건에서 내 단위 테스트를 단위 테스트 할 수 있습니까 (또는 그러한 단위 테스트도 필요합니까)?

고맙습니다.

답변

2

동시성은 응용 프로그램과 데이터베이스의 두 가지 수준에서 발생합니다.

응용 프로그램 수준에서 여러 사용자가 겹치는 편집 세션이있을 수 있습니다. 어떤 시점에서 사용자는 버전을 저장하고 다음 버전도 저장하지만 현재 디자인에서 마지막 편집이 어떤 버전의 브랜칭인지 알 수있는 방법이없는 것처럼 보입니다.이 정보는 어디에도 없습니다. 언급 된 INSERT.

데이터베이스 수준의 동시성은 다른 문제이며, 동시에 실행되는 트랜잭션에 관련됩니다.

동시성을 처리하는 데이터베이스 프리미티브로 응용 프로그램 동시성을 해결하려는 경우 사용자가 편집을 마칠 때까지 열려있는 트랜잭션을 유지해야합니다. 이는 임의의 오랜 시간 동안 의미하며 이는 시작에 있지 않습니다. 데이터베이스 설계.

우선 동시 편집을 처리하기위한 응용 프로그램 및 디자인 전략을 파악한 다음 동시 트랜잭션 처리를위한 데이터베이스 전략, 즉 "저장"을 동시에 수행해야합니다. 데이터를 업데이트하는 트랜잭션은 병렬로 실행됩니다. 이들은 완전히 다른 것들입니다. 동일한 작업을 수행하려고하는 어떤 다른 트랜잭션이 될 수 있도록 동시 트랜잭션, 문제를 피하기 위해 하나의 일반적인 방법에 관한


는 다른 작업을 수행하기 전에 쓰기 트랜잭션의 시작 부분에 문서를 잠그는 것입니다 동시 변경이 커밋 (또는 롤백) 될 때까지 차단됩니다. 업데이트를 직렬화하는 가장 간단한 방법이지만 동시에 차단되지 않는 다른 아티클에 대한 업데이트가 충분히 세분화되어있는 것으로 가정합니다.

이상적으로 path 당 하나의 행만있는 article 테이블이 있어야합니다 (다른 테이블에 저장되는 리비전과 독립적 임). 그런 다음 해당 행을 SELECT ... FOR UPDATE으로 잠그면 브랜치 또는 복잡한 업데이트를 수행하는 쿼리 집합이 동일한 아티클에 대한 동시 변경으로 인해 고민하지 않고도 작동 할 수 있습니다.

또 다른 (거친) 방법은 직렬화 가능 격리 수준을 사용하고 실패한 트랜잭션을 SQLSTATE이 직렬화 실패를 나타내도록 다시 시도하는 것입니다.

+0

맞습니다. 수정 사항에 따라 기반이되는 버전을 알 수 없습니다. 클라이언트는 또한 그들이 기반으로하는 기사 ID를 보내야합니다, 나는 그것을 업데이 트합니다. 그러나, 나는 응용 프로그램 세션이 어떻게 관련이 있는지 잘 모른다. 두 명의 사용자가 동시에 편집 할 수 있습니다. 먼저 저장하면 다른 하나는 저장 될 때 충돌에 대해 통보됩니다. 그렇다면 데이터베이스 동시성 만 처리하면 안됩니까? 그게 내가 어려움을 겪고있는거야. – hgl

+0

@hgl : 데이터베이스 동시성 측면에 대해 더 자세히 설명하도록 편집되었습니다. –