Source code for relstorage.adapters.sqlite.oidallocator
# -*- coding: utf-8 -*-################################################################################ Copyright (c) 2019 Zope Foundation and Contributors.# All Rights Reserved.## This software is subject to the provisions of the Zope Public License,# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS# FOR A PARTICULAR PURPOSE.###############################################################################"""sqlite3 adapter for RelStorage."""from__future__importabsolute_importfrom__future__importdivisionfrom__future__importprint_functionimportsqlite3importthreadingfromzope.interfaceimportimplementerfromrelstorage._utilimportconsumefrom..interfacesimportIOIDAllocatorfrom..oidallocatorimportAbstractRangedOIDAllocator
[docs]@implementer(IOIDAllocator)classSqlite3OIDAllocator(AbstractRangedOIDAllocator):# Even though we use the new_oid table like AbstractTableOIDAllocator# does, because we have to take exclusive locks *anyway*, we can# ensure that it only ever has a single increasing row.def__init__(self,db_path,driver):super().__init__()self.db_path=db_pathself.lock=threading.Lock()self.driver=driverself._connection=Nonedefnew_instance(self):returnselfdefrelease(self):self.close()defclose(self):withself.lock:ifself._connection:self._connection.close()self._connection=None# This is actually the last OID we returned. We begin allocating beginning with# the *next* integer._new_oid_query='CREATE TABLE new_oid (zoid INTEGER PRIMARY KEY NOT NULL);'def_connect(self):ifself._connectionisNone:conn=self.driver.connect_to_file(self.db_path,mmap_size=1024*1024*10,# try to keep the whole thing in memory.override_pragmas={# We can always reconstruct the contents of this file from the database# itself, and speed is utterly critical.'journal_mode':'off','synchronous':'off',})try:consume(conn.execute('SELECT count(*) from new_oid'))exceptsqlite3.OperationalError:conn.executescript(self._new_oid_query+""" INSERT OR REPLACE INTO new_oid SELECT MAX(x) FROM ( SELECT 0 x UNION ALL SELECT MAX(zoid) FROM new_oid ) """)self._connection=connreturnself._connectiondef_set_min_oid_from_range(self,cursor,n):# Recall that the very first write to the database will cause# the file to be locked against further writes. So there's some# benefit in avoiding writes if they're not needed. Because we# keep this in a separate database as well, we can keep the connection# in autocommit mode.withself.lock:# We've left the underlying connection in autocommit mode.conn=self._connect()rows=conn.execute('SELECT zoid FROM new_oid WHERE zoid < ?',(n,)).fetchall()ifrows:# Narf, we need to execute a write transaction.consume(conn.execute('UPDATE new_oid SET zoid = :new WHERE zoid < :new',{'new':n}))defnew_oids(self,cursor=None):returnself.new_oids_no_cursor()defnew_oids_no_cursor(self):withself.lock:conn=self._connect()consume(conn.execute('BEGIN IMMEDIATE TRANSACTION'))row,=conn.execute('SELECT zoid FROM new_oid')conn.execute('UPDATE new_oid SET zoid = zoid + 1')conn.commit()returnself._oid_range_around(row[0]+1)defreset_oid(self,cursor=None):withself.lock:self._connect().execute('UPDATE new_oid SET zoid = 0')