2012-03-21 3 views
1

저는 서버와 클라이언트를 가지고 있습니다.zodb : 데이터베이스 충돌이 실패했습니다.

클라이언트가 요청을 보냅니다. 요청에 연결된 특정 키가 있습니다 (예 : a-1, a-2, b-1, b-4.

동일한 키에 대한 두 개의 요청이 동시에 들어오는 경우 동일한 데이터 구조가 수정되므로 충돌 오류가 발생합니다.

클라이언트가 한 번에 같은 키의 두 요청을 보내지 않도록 조정할 수 있습니다. 그러나이 시스템을 여러 클라이언트와 함께 사용하고 싶습니다. 클라이언트가 서버에 보내는 내용을 조정하게하는 것은 어리석은 행동입니다. 그 대신, 동일한 키를 가진 다른 요청이 완료 될 때까지 해당 키가 이미 수정중인 경우 서버가 특정 키의 요청을 단순히 차단하도록합니다.

이렇게하려면 잠금 시스템을 만들었습니다. 서버에서 함수의 시작 부분에서, 내가 할 : KEY_LOCKSthreading.Lock들에 DICT 매핑 키입니다

key = ... 
print "Acquiring %s lock..." % (key,) 
KEY_LOCKS[key].acquire() 
print "%s lock acquired." % (key,) 
def after_commit_hook(success): 
    KEY_LOCKS[key].release() 
    print "(after %s commit): Released %s lock" % (('failed', 'successful')[success], key) 
transaction.get().addAfterCommitHook(after_commit_hook) 

. 그런 다음 영구 데이터 구조를 수정하는 코드를 따릅니다.

내가 예상 할 수있는 것은 이미 처리중인 키에 대한 요청이 들어 오면 잠금을 획득 할 때 차단된다는 것입니다. 이전 요청 이 이미 커밋 된 일 때만 (따라서 충돌 오류가 발생하지 않음) 새 요청이 다시 시작됩니다. 요청은 잠금을 얻을 때까지 충돌하지 않습니다.

요청의 대부분은 잘 작동 :

Acquiring a-b lock... 
a-b lock acquired. 
(after successful commit): Released a-b lock 
Acquiring a-c lock... 
a-c lock acquired. 
(after successful commit): Released a-c lock 

그러나 여전히 같은 키가 전송되는 문제가 있습니다, 잠금 보인다하더라도 작동합니다 :

Acquiring q-q lock... 
q-q lock acquired. 
Acquiring q-q lock... 
(after successful commit): Released q-q lock 
q-q lock acquired. 
(after failed commit): Released q-q lock 
repoze.retry retrying, count = 1 
Traceback (most recent call last): 
... 
ConflictError: database conflict error (oid 0x13009b, class persistent.list.PersistentList) 

그리고 요청이 재 시도됩니다. q-q lock은 성공적인 커밋 후에 만 ​​획득되었습니다.

무엇을 제공합니까? 이 시스템이 충돌 오류를 방지하지 않는 이유는 무엇입니까? 내 가정은 어디에서 잘못 되었습니까?


편집 : 음, 경우에, 나는 transaction.begin()을 넣어 transaction.get().addAfterCommitHook(after_commit_hook) 라인 전에, 그것은 작동합니다. 내 인생에서 나는 그 이유를 알 수 없다. transaction.begin() 라인 전에, 내 코드의 전체는 다음과 같습니다

post = request.params 
if not post: return Response("No data!") 

data = eval(post['data']) 
time_parsed = time.time() 
my_app = request.context 

이 내 문제를 해결하지만 퍼팅 아니에요 난 아직도 알고 싶어 원인 대답 '로 : 왜 충돌 오류를 주는가 I 돈 경우 바로 전에 신선한 거래를 시작하지 않습니까?

+1

ZODB-dev 메일 링리스트에 게시 해보십시오. 답변을 얻은 경우 여기에 게시하십시오. – sdupton

+0

@sdupton : 감사합니다. – Claudiu

답변

3

ZODB는 트랜잭션이 시작된 순간부터 일관된 뷰를 제공합니다. 즉, 스레드가 새로운 트랜잭션이 시작될 때까지 다른 스레드가 만든 데이터베이스에서 변경 사항을 볼 수 없다는 것입니다. 이것은 Multiversion Concurrency Control이라는 데이터베이스의 기본 기능입니다.

즉, 잠금을 사용하여 응용 프로그램 스레드가 충돌하지 않게하려면 잠금을 사용할 수있게되면 새 트랜잭션을 시작해야합니다.

제 생각에는 잠금은 피할 수있는 성능 병목입니다. 잠금 장치를 길게 길게 설정할수록 일치하지 않는 데이터 (시작 상태와 데이터베이스 상태)에 빠질 가능성이 커집니다.

Zope에서는 대신 낙관적 인 방법이 사용됩니다. 충돌 오류가 발생하면 트랜잭션이 중단되고 처음부터 다시 시도됩니다. 트랜잭션이 짧고 업무가 빠르다면 대부분의 잠금 문제를 피할 수 있습니다. 대신 영구 변경이 변경되어 충돌을 일으킬 때마다 데이터베이스에 대한 변경 사항을 다시 계산하면됩니다.

+0

아, 그건 의미가 있습니다. 설명 주셔서 감사합니다! 재 : 잠금, 그것은 실제로 불필요한 수 있습니다. 나는 그것없이 내가 할 수있는 것을 보게 될 것이다. – Claudiu