mirror of
https://github.com/bringout/oca-technical.git
synced 2026-04-19 09:32:06 +02:00
Initial commit: OCA Technical packages (595 packages)
This commit is contained in:
commit
2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions
78
odoo-bringout-oca-connector-connector/connector/database.py
Normal file
78
odoo-bringout-oca-connector-connector/connector/database.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# Copyright 2013 Camptocamp SA
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html)
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
import struct
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def pg_try_advisory_lock(env, lock):
|
||||
"""Try to acquire a Postgres transactional advisory lock.
|
||||
|
||||
The function tries to acquire a lock, returns a boolean indicating
|
||||
if it could be obtained or not. An acquired lock is released at the
|
||||
end of the transaction.
|
||||
|
||||
A typical use is to acquire a lock at the beginning of an importer
|
||||
to prevent 2 jobs to do the same import at the same time. Since the
|
||||
record doesn't exist yet, we can't put a lock on a record, so we put
|
||||
an advisory lock.
|
||||
|
||||
Example:
|
||||
- Job 1 imports Partner A
|
||||
- Job 2 imports Partner B
|
||||
- Partner A has a category X which happens not to exist yet
|
||||
- Partner B has a category X which happens not to exist yet
|
||||
- Job 1 import category X as a dependency
|
||||
- Job 2 import category X as a dependency
|
||||
|
||||
Since both jobs are executed concurrently, they both create a record
|
||||
for category X so we have duplicated records. With this lock:
|
||||
|
||||
- Job 1 imports Partner A, it acquires a lock for this partner
|
||||
- Job 2 imports Partner B, it acquires a lock for this partner
|
||||
- Partner A has a category X which happens not to exist yet
|
||||
- Partner B has a category X which happens not to exist yet
|
||||
- Job 1 import category X as a dependency, it acquires a lock for
|
||||
this category
|
||||
- Job 2 import category X as a dependency, try to acquire a lock
|
||||
but can't, Job 2 is retried later, and when it is retried, it
|
||||
sees the category X created by Job 1.
|
||||
|
||||
The lock is acquired until the end of the transaction.
|
||||
|
||||
Usage example:
|
||||
|
||||
::
|
||||
|
||||
lock_name = 'import_record({}, {}, {}, {})'.format(
|
||||
self.backend_record._name,
|
||||
self.backend_record.id,
|
||||
self.model._name,
|
||||
self.external_id,
|
||||
)
|
||||
if pg_try_advisory_lock(lock_name):
|
||||
# do sync
|
||||
else:
|
||||
raise RetryableJobError('Could not acquire advisory lock',
|
||||
seconds=2,
|
||||
ignore_retry=True)
|
||||
|
||||
:param env: the Odoo Environment
|
||||
:param lock: The lock name. Can be anything convertible to a
|
||||
string. It needs to represents what should not be synchronized
|
||||
concurrently so usually the string will contain at least: the
|
||||
action, the backend type, the backend id, the model name, the
|
||||
external id
|
||||
:return True/False whether lock was acquired.
|
||||
"""
|
||||
hasher = hashlib.sha1(str(lock).encode())
|
||||
# pg_lock accepts an int8 so we build an hash composed with
|
||||
# contextual information and we throw away some bits
|
||||
int_lock = struct.unpack("q", hasher.digest()[:8])
|
||||
|
||||
env.cr.execute("SELECT pg_try_advisory_xact_lock(%s);", (int_lock,))
|
||||
acquired = env.cr.fetchone()[0]
|
||||
return acquired
|
||||
Loading…
Add table
Add a link
Reference in a new issue