Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
ZODB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Nicolas Wavrant
ZODB
Commits
c028ea24
Commit
c028ea24
authored
Oct 30, 2008
by
Jim Fulton
Browse files
Options
Browse Files
Download
Plain Diff
tag
parents
16dd2c12
1a896e9c
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
287 additions
and
327 deletions
+287
-327
src/CHANGES.txt
src/CHANGES.txt
+2
-0
src/ZODB/DB.py
src/ZODB/DB.py
+83
-120
src/ZODB/DemoStorage.py
src/ZODB/DemoStorage.py
+35
-12
src/ZODB/DemoStorage.test
src/ZODB/DemoStorage.test
+110
-22
src/ZODB/component.xml
src/ZODB/component.xml
+1
-2
src/ZODB/config.py
src/ZODB/config.py
+10
-8
src/ZODB/historical_connections.txt
src/ZODB/historical_connections.txt
+42
-156
src/ZODB/tests/dbopen.txt
src/ZODB/tests/dbopen.txt
+4
-4
src/ZODB/tests/testhistoricalconnections.py
src/ZODB/tests/testhistoricalconnections.py
+0
-3
No files found.
src/CHANGES.txt
View file @
c028ea24
...
@@ -37,6 +37,8 @@ New Features
...
@@ -37,6 +37,8 @@ New Features
- Multi-version concurrency control and iteration
- Multi-version concurrency control and iteration
- Explicit support dfor demo-storage stacking via push and pop methods.
- Wen calling ZODB.DB to create a database, you can now pass a file
- Wen calling ZODB.DB to create a database, you can now pass a file
name, rather than a storage to use a file storage.
name, rather than a storage to use a file storage.
...
...
src/ZODB/DB.py
View file @
c028ea24
This diff is collapsed.
Click to expand it.
src/ZODB/DemoStorage.py
View file @
c028ea24
...
@@ -19,7 +19,9 @@ to be layered over a base database.
...
@@ -19,7 +19,9 @@ to be layered over a base database.
The base storage must not change.
The base storage must not change.
"""
"""
import
os
import
random
import
random
import
weakref
import
tempfile
import
tempfile
import
threading
import
threading
import
ZODB.blob
import
ZODB.blob
...
@@ -36,35 +38,41 @@ class DemoStorage(object):
...
@@ -36,35 +38,41 @@ class DemoStorage(object):
ZODB
.
interfaces
.
IStorageIteration
,
ZODB
.
interfaces
.
IStorageIteration
,
)
)
def
__init__
(
self
,
name
=
None
,
base
=
None
,
changes
=
None
,
def
__init__
(
self
,
name
=
None
,
base
=
None
,
changes
=
None
):
keep_base_open
=
False
):
self
.
_keep_base_open
=
keep_base_open
if
base
is
None
:
if
base
is
None
:
base
=
ZODB
.
MappingStorage
.
MappingStorage
()
base
=
ZODB
.
MappingStorage
.
MappingStorage
()
self
.
_temporary_base
=
True
else
:
self
.
_temporary_base
=
False
self
.
base
=
base
self
.
base
=
base
if
changes
is
None
:
if
changes
is
None
:
changes
=
ZODB
.
MappingStorage
.
MappingStorage
()
changes
=
ZODB
.
MappingStorage
.
MappingStorage
()
zope
.
interface
.
alsoProvides
(
self
,
ZODB
.
interfaces
.
IBlobStorage
)
zope
.
interface
.
alsoProvides
(
self
,
ZODB
.
interfaces
.
IBlobStorage
)
self
.
_temporary_changes
=
True
self
.
_temporary_changes
=
True
self
.
_blob_dir
=
None
else
:
else
:
if
ZODB
.
interfaces
.
IBlobStorage
.
providedBy
(
changes
):
if
ZODB
.
interfaces
.
IBlobStorage
.
providedBy
(
changes
):
zope
.
interface
.
alsoProvides
(
self
,
ZODB
.
interfaces
.
IBlobStorage
)
zope
.
interface
.
alsoProvides
(
self
,
ZODB
.
interfaces
.
IBlobStorage
)
self
.
_temporary_changes
=
False
self
.
_temporary_changes
=
False
self
.
changes
=
changes
self
.
changes
=
changes
if
name
is
None
:
if
name
is
None
:
name
=
'DemoStorage(%r, %r)'
%
(
base
.
getName
(),
changes
.
getName
())
name
=
'DemoStorage(%r, %r)'
%
(
base
.
getName
(),
changes
.
getName
())
self
.
__name__
=
name
self
.
__name__
=
name
self
.
_copy_methods_from_changes
(
changes
)
self
.
_copy_methods_from_changes
(
changes
)
def
_blobify
(
self
):
def
_blobify
(
self
):
if
self
.
_temporary_changes
and
self
.
_blob_dir
is
None
:
if
(
self
.
_temporary_changes
and
self
.
_blob_dir
=
tempfile
.
mkdtemp
(
'blobs'
)
isinstance
(
self
.
changes
,
ZODB
.
MappingStorage
.
MappingStorage
)
self
.
changes
=
ZODB
.
blob
.
BlobStorage
(
self
.
_blob_dir
,
self
.
changes
)
):
blob_dir
=
tempfile
.
mkdtemp
(
'.demoblobs'
)
_temporary_blobdirs
[
weakref
.
ref
(
self
,
cleanup_temporary_blobdir
)
]
=
blob_dir
self
.
changes
=
ZODB
.
blob
.
BlobStorage
(
blob_dir
,
self
.
changes
)
self
.
_copy_methods_from_changes
(
self
.
changes
)
self
.
_copy_methods_from_changes
(
self
.
changes
)
return
True
return
True
...
@@ -73,11 +81,10 @@ class DemoStorage(object):
...
@@ -73,11 +81,10 @@ class DemoStorage(object):
self
.
changes
.
cleanup
()
self
.
changes
.
cleanup
()
def
close
(
self
):
def
close
(
self
):
if
not
self
.
_
keep_base_open
:
if
not
self
.
_
temporary_base
:
self
.
base
.
close
()
self
.
base
.
close
()
self
.
changes
.
close
()
if
not
self
.
_temporary_changes
:
if
getattr
(
self
,
'_blob_dir'
,
''
):
self
.
changes
.
close
()
ZODB
.
blob
.
remove_committed_dir
(
self
.
_blob_dir
)
def
_copy_methods_from_changes
(
self
,
changes
):
def
_copy_methods_from_changes
(
self
,
changes
):
for
meth
in
(
for
meth
in
(
...
@@ -195,6 +202,13 @@ class DemoStorage(object):
...
@@ -195,6 +202,13 @@ class DemoStorage(object):
pass
# The gc arg isn't supported. Don't pack
pass
# The gc arg isn't supported. Don't pack
raise
raise
def
pop
(
self
):
self
.
changes
.
close
()
return
self
.
base
def
push
(
self
,
changes
=
None
):
return
self
.
__class__
(
base
=
self
,
changes
=
changes
)
def
store
(
self
,
oid
,
serial
,
data
,
version
,
transaction
):
def
store
(
self
,
oid
,
serial
,
data
,
version
,
transaction
):
assert
version
==
''
,
"versions aren't supported"
assert
version
==
''
,
"versions aren't supported"
...
@@ -231,3 +245,12 @@ class DemoStorage(object):
...
@@ -231,3 +245,12 @@ class DemoStorage(object):
if
self
.
_blobify
():
if
self
.
_blobify
():
return
self
.
changes
.
temporaryDirectory
()
return
self
.
changes
.
temporaryDirectory
()
raise
raise
_temporary_blobdirs
=
{}
def
cleanup_temporary_blobdir
(
ref
,
_temporary_blobdirs
=
_temporary_blobdirs
,
# Make sure it stays around
):
blob_dir
=
_temporary_blobdirs
.
pop
(
ref
,
None
)
if
blob_dir
and
os
.
path
.
exists
(
blob_dir
):
ZODB
.
blob
.
remove_committed_dir
(
blob_dir
)
src/ZODB/DemoStorage.test
View file @
c028ea24
...
@@ -120,37 +120,66 @@ Undo methods are simply copied from the changes storage:
...
@@ -120,37 +120,66 @@ Undo methods are simply copied from the changes storage:
... ]
... ]
[True, True, True, True]
[True, True, True, True]
>>> db.close()
Normally, when we close a demo storage, the changes and base storages
Storage Stacking
are closed:
================
>>> db.close()
A common use case is to stack demo storages. DemoStorage provides
>>> base._file.closed
some helper functions to help with this. The push method, just
creates a new demo storage who'
s
base
is
the
original
demo
storage
:
>>>
demo
=
DemoStorage
()
>>>
demo2
=
demo
.
push
()
>>>
demo2
.
base
is
demo
True
True
>>> changes._file.closed
We
can
also
supply
an
explicit
changes
storage
,
if
we
wish
:
>>>
from
ZODB
.
MappingStorage
import
MappingStorage
>>>
changes
=
MappingStorage
()
>>>
demo3
=
demo2
.
push
(
changes
)
>>>
demo3
.
changes
is
changes
,
demo3
.
base
is
demo2
(
True
,
True
)
The
pop
method
closes
the
changes
storage
and
returns
the
base
*
without
*
closing
it
:
>>>
demo3
.
pop
()
is
demo2
True
True
A common use case is to stack multiple DemoStorages, returning to a
>>>
changes
.
opened
()
previous state by popping a DemoStorage off the stack. In this case,
False
we want to leave the base storage open:
>>> base = FileStorage('
base
.
fs
', read_only=True)
Special
backward
compatibility
support
>>> storage = DemoStorage(base=base, keep_base_open=True)
--------------------------------------
Here, we didn'
t
specify
a
changes
storage
.
A
MappingStorage
wa
s
Normally
,
when
a
demo
storage
is
closed
,
it
's base and change
s
automatically
creat
ed
:
storage are clos
ed:
>>>
type
(
storage
.
changes
)
.
__name__
>>> demo = DemoStorage(base=MappingStorage(), changes=MappingStorage())
'MappingStorage'
>>> demo.close()
>>> demo.base.opened(), demo.changes.opened()
(False, False)
Because
we
specified
the
keep_base_open
option
,
the
base
storage
is
Older versions of DemoStorage didn'
t
have
a
separate
changes
storage
left
open
when
we
close
the
DemoStorage
:
and
didn
't close or discard their changes when they were closed. When
a stack was built solely of demo storages, the close method
effectively did nothing. To maintain backward compatibility, when no
base or changes storage is supplied in the constructor, the underlying
storage created by the demo storage isn'
t
closed
by
the
demo
storage
.
This
backward
-
compatibility
is
deprecated
.
>>>
storage
.
close
()
>>>
demo
=
DemoStorage
()
>>>
base
.
_file
.
closed
>>>
demo
.
close
()
False
>>>
demo
.
changes
.
opened
(),
demo
.
base
.
opened
()
>>>
storage
.
changes
.
opened
()
(
True
,
True
)
False
>>>
demo
=
DemoStorage
(
base
=
MappingStorage
())
>>>
demo2
=
demo
.
push
()
>>>
demo2
.
close
()
>>>
demo2
.
changes
.
opened
(),
demo2
.
base
.
base
.
opened
()
(
True
,
False
)
Blob
Support
Blob
Support
============
============
...
@@ -236,6 +265,65 @@ storage wrapped around it when necessary:
...
@@ -236,6 +265,65 @@ storage wrapped around it when necessary:
.. Check that the temporary directory is gone
.. Check that the temporary directory is gone
For now, it won'
t
go
until
the
storage
does
.
>>>
transaction
.
abort
()
>>>
conn
.
close
()
>>>
blobdir
=
storage
.
temporaryDirectory
()
>>>
del
db
,
conn
,
storage
,
_
>>>
import
gc
>>>
_
=
gc
.
collect
()
>>>
import
os
>>>
import
os
>>>
os
.
path
.
exists
(
storage
.
temporaryDirectory
()
)
>>>
os
.
path
.
exists
(
blobdir
)
False
False
ZConfig
support
===============
You
can
configure
demo
storages
using
ZConfig
,
using
name
,
changes
,
and
base
options
:
>>>
import
ZODB
.
config
>>>
storage
=
ZODB
.
config
.
storageFromString
(
"""
... <demostorage>
... </demostorage>
... """
)
>>>
storage
.
getName
()
"DemoStorage('MappingStorage', 'MappingStorage')"
>>>
storage
=
ZODB
.
config
.
storageFromString
(
"""
... <demostorage>
... <filestorage base>
... path base.fs
... </filestorage>
...
... <filestorage changes>
... path changes.fs
... </filestorage>
... </demostorage>
... """
)
>>>
storage
.
getName
()
"DemoStorage('base.fs', 'changes.fs')"
>>>
storage
.
close
()
>>>
storage
=
ZODB
.
config
.
storageFromString
(
"""
... <demostorage>
... name bob
... <filestorage>
... path base.fs
... </filestorage>
...
... <filestorage changes>
... path changes.fs
... </filestorage>
... </demostorage>
... """
)
>>>
storage
.
getName
()
'bob'
>>>
storage
.
base
.
getName
()
'base.fs'
>>>
storage
.
close
()
src/ZODB/component.xml
View file @
c028ea24
...
@@ -175,8 +175,7 @@
...
@@ -175,8 +175,7 @@
<sectiontype
name=
"demostorage"
datatype=
".DemoStorage"
<sectiontype
name=
"demostorage"
datatype=
".DemoStorage"
implements=
"ZODB.storage"
>
implements=
"ZODB.storage"
>
<key
name=
"name"
/>
<key
name=
"name"
/>
<section
type=
"ZODB.storage"
name=
"*"
attribute=
"base"
/>
<multisection
type=
"ZODB.storage"
name=
"*"
attribute=
"factories"
/>
<section
type=
"ZODB.storage"
name=
"changes"
attribute=
"changes"
/>
</sectiontype>
</sectiontype>
...
...
src/ZODB/config.py
View file @
c028ea24
...
@@ -120,15 +120,17 @@ class MappingStorage(BaseConfig):
...
@@ -120,15 +120,17 @@ class MappingStorage(BaseConfig):
class
DemoStorage
(
BaseConfig
):
class
DemoStorage
(
BaseConfig
):
def
open
(
self
):
def
open
(
self
):
base
=
changes
=
None
for
factory
in
self
.
config
.
factories
:
if
factory
.
name
==
'changes'
:
changes
=
factory
.
open
()
else
:
if
base
is
None
:
base
=
factory
.
open
()
else
:
raise
ValueError
(
"Too many base storages defined!"
)
from
ZODB.DemoStorage
import
DemoStorage
from
ZODB.DemoStorage
import
DemoStorage
if
self
.
config
.
base
:
base
=
self
.
config
.
base
.
open
()
else
:
base
=
None
if
self
.
config
.
changes
:
changes
=
self
.
config
.
changes
.
open
()
else
:
changes
=
None
return
DemoStorage
(
self
.
config
.
name
,
base
=
base
,
changes
=
changes
)
return
DemoStorage
(
self
.
config
.
name
,
base
=
base
,
changes
=
changes
)
class
FileStorage
(
BaseConfig
):
class
FileStorage
(
BaseConfig
):
...
...
src/ZODB/historical_connections.txt
View file @
c028ea24
...
@@ -13,11 +13,7 @@ development continues on a "development" head.
...
@@ -13,11 +13,7 @@ development continues on a "development" head.
A database can be opened historically ``at`` or ``before`` a given transaction
A database can be opened historically ``at`` or ``before`` a given transaction
serial or datetime. Here's a simple example. It should work with any storage
serial or datetime. Here's a simple example. It should work with any storage
that supports ``loadBefore``. Unfortunately that does not include
that supports ``loadBefore``.
MappingStorage, so we use a FileStorage instance. Also unfortunately, as of
this writing there is no reliable way to determine if a storage truly
implements loadBefore, or if it simply returns None (as in BaseStorage), other
than reading code.
We'll begin our example with a fairly standard set up. We
We'll begin our example with a fairly standard set up. We
...
@@ -28,11 +24,8 @@ We'll begin our example with a fairly standard set up. We
...
@@ -28,11 +24,8 @@ We'll begin our example with a fairly standard set up. We
- modify the database again; and
- modify the database again; and
- commit a transaction.
- commit a transaction.
>>> import ZODB.FileStorage
>>> import ZODB.MappingStorage
>>> storage = ZODB.FileStorage.FileStorage(
>>> db = ZODB.MappingStorage.DB()
... 'HistoricalConnectionTests.fs', create=True)
>>> import ZODB
>>> db = ZODB.DB(storage)
>>> conn = db.open()
>>> conn = db.open()
>>> import persistent.mapping
>>> import persistent.mapping
...
@@ -42,14 +35,13 @@ We'll begin our example with a fairly standard set up. We
...
@@ -42,14 +35,13 @@ We'll begin our example with a fairly standard set up. We
>>> import transaction
>>> import transaction
>>> transaction.commit()
>>> transaction.commit()
We wait for some t
time to pass
, and then make some other changes.
We wait for some t
ime to pass, record he time
, and then make some other changes.
>>> import time
>>> import time
>>> t = time.time()
>>> t = time.time()
>>> while time.time() <= t:
>>> while time.time() <= t:
... time.sleep(.001)
... time.sleep(.001)
>>> import datetime
>>> import datetime
>>> now = datetime.datetime.utcnow()
>>> now = datetime.datetime.utcnow()
...
@@ -164,186 +156,80 @@ historical connection should be kept.
...
@@ -164,186 +156,80 @@ historical connection should be kept.
>>> db.getHistoricalTimeout()
>>> db.getHistoricalTimeout()
400
400
All three of these values can be specified in a ZConfig file. We're using
All three of these values can be specified in a ZConfig file.
mapping storage for simplicity, but remember, as we said at the start of this
document, mapping storage will not work for historical connections (and in fact
may seem to work but then fail confusingly) because it does not implement
loadBefore.
>>> import ZODB.config
>>> import ZODB.config
>>> db2 = ZODB.config.databaseFromString('''
>>> db2 = ZODB.config.databaseFromString('''
... <zodb>
... <zodb>
... <mappingstorage/>
... <mappingstorage/>
... historical-pool-size
5
... historical-pool-size
3
... historical-cache-size 1500
... historical-cache-size 1500
... historical-timeout 6m
... historical-timeout 6m
... </zodb>
... </zodb>
... ''')
... ''')
>>> db2.getHistoricalPoolSize()
>>> db2.getHistoricalPoolSize()
5
3
>>> db2.getHistoricalCacheSize()
>>> db2.getHistoricalCacheSize()
1500
1500
>>> db2.getHistoricalTimeout()
>>> db2.getHistoricalTimeout()
360
360
Let's actually look at these values at work by shining some light into what
has been a black box up to now. We'll actually do some white box examination
of what is going on in the database, pools and connections.
Historical connections are held in a single connection pool with mappings
from the ``before`` TID to available connections. First we'll put a new
pool on the database so we have a clean slate.
>>> historical_conn.close()
>>> from ZODB.DB import KeyedConnectionPool
>>> db.historical_pool = KeyedConnectionPool(
... db.historical_pool.size, db.historical_pool.timeout)
Now lets look what happens to the pool when we create and close an historical
The pool lets us reuse connections. To see this, we'll open some
connection
.
connection
s, close them, and then open them again:
>>> pool = db.historical_pool
>>> conns1 = [db2.open(before=serial) for i in range(4)]
>>> len(pool.all)
>>> _ = [c.close() for c in conns1]
0
>>> conns2 = [db2.open(before=serial) for i in range(4)]
>>> len(pool.available)
0
>>> historical_conn = db.open(
... transaction_manager=transaction1, before=serial)
>>> len(pool.all)
1
>>> len(pool.available)
0
>>> historical_conn in pool.all
True
>>> historical_conn.close()
>>> len(pool.all)
1
>>> len(pool.available)
1
>>> pool.available.keys()[0] == serial
True
>>> len(pool.available.values()[0])
1
Now
we'll open and close two for the same serial to see what happens to
the
Now
let's look at what we got. The first connection in conns 2 is
the
data structures
.
last connection in conns1, because it was the last connection closed
.
>>> historical_conn is db.open(
>>> conns2[0] is conns1[-1]
... transaction_manager=transaction1, before=serial)
True
True
>>> len(pool.all)
1
>>> len(pool.available)
0
>>> transaction2 = transaction.TransactionManager()
>>> historical_conn2 = db.open(
... transaction_manager=transaction2, before=serial)
>>> len(pool.all)
2
>>> len(pool.available)
0
>>> historical_conn2.close()
>>> len(pool.all)
2
>>> len(pool.available)
1
>>> len(pool.available.values()[0])
1
>>> historical_conn.close()
>>> len(pool.all)
2
>>> len(pool.available)
1
>>> len(pool.available.values()[0])
2
If you change the historical cache size, that changes the size of the
Also for the next two:
persistent cache on our connection.
>>> historical_conn._cache.cache_size
>>> (conns2[1] is conns1[-2]), (conns2[2] is conns1[-3])
2000
(True, True)
>>> db.setHistoricalCacheSize(1500)
>>> historical_conn._cache.cache_size
1500
Now let's look at pool sizes. We'll set it to two, then open and close three
But not for the last:
connections. We should end up with only two available connections.
>>> db.setHistoricalPoolSize(2)
>>> conns2[3] is conns1[-4]
False
>>> historical_conn = db.open(
Because the pool size was set to 3.
... transaction_manager=transaction1, before=serial)
>>> historical_conn2 = db.open(
... transaction_manager=transaction2, before=serial)
>>> transaction3 = transaction.TransactionManager()
>>> historical_conn3 = db.open(
... transaction_manager=transaction3, at=historical_serial)
>>> len(pool.all)
3
>>> len(pool.available)
0
>>> historical_conn3.close()
Connections are also discarded if they haven't been used in a while.
>>> len(pool.all)
To see this, let's close two of the connections:
3
>>> len(pool.available)
1
>>> len(pool.available.values()[0])
1
>>> historical_conn2.close()
>>> conns2[0].close(); conns2[1].close()
>>> len(pool.all)
3
>>> len(pool.available)
2
>>> len(pool.available.values()[0])
1
>>> len(pool.available.values()[1])
1
>>> historical_conn.close()
We'l also set the historical timeout to be very low:
>>> len(pool.all)
2
>>> len(pool.available)
1
>>> len(pool.available.values()[0])
2
Notice it dumped the one that was closed at the earliest time.
>>> db2.setHistoricalTimeout(.01)
>>> time.sleep(.1)
>>> conns2[2].close(); conns2[3].close()
Finally, we'll look at the timeout. We'll need to monkeypatch ``time`` for
Now, when we open 4 connections:
this. (The funky __import__ of DB is because some ZODB __init__ shenanigans
make the DB class mask the DB module.)
>>> db.getHistoricalTimeout()
>>> conns1 = [db2.open(before=serial) for i in range(4)]
400
>>> import time
>>> delta = 200
>>> def stub_time():
... return time.time() + delta
...
>>> DB_module = __import__('ZODB.DB', globals(), locals(), ['chicken'])
>>> original_time = DB_module.time
>>> DB_module.time = stub_time
>>> historical_conn = db.open(before=serial)
We'll see that only the last 2 connections from conn2 are in the
result:
>>> len(pool.all)
>>> [c in conns1 for c in conns2]
2
[False, False, True, True]
>>> len(pool.available)
1
A close or an open will do garbage collection on the timed out connections.
>>> delta += 200
If you change the historical cache size, that changes the size of the
>>> historical_conn.close()
persistent cache on our connection.
>>> len(pool.all)
>>> historical_conn._cache.cache_size
1
2000
>>> len(pool.available)
>>> db.setHistoricalCacheSize(1500)
1
>>> historical_conn._cache.cache_size
>>> len(pool.available.values()[0])
1500
1
Invalidations
Invalidations
=============
=============
...
...
src/ZODB/tests/dbopen.txt
View file @
c028ea24
...
@@ -239,12 +239,12 @@ Closing connections adds them to the stack:
...
@@ -239,12 +239,12 @@ Closing connections adds them to the stack:
Closing another one will purge the one with MARKER 0 from the stack
Closing another one will purge the one with MARKER 0 from the stack
(since it was the first added to the stack):
(since it was the first added to the stack):
>>> [c.MARKER for
c in pool.available.values()
]
>>> [c.MARKER for
(t, c) in pool.available
]
[0, 1, 2]
[0, 1, 2]
>>> conns[0].close() # MARKER 3
>>> conns[0].close() # MARKER 3
>>> len(pool.available), len(pool.all)
>>> len(pool.available), len(pool.all)
(3, 5)
(3, 5)
>>> [c.MARKER for
c in pool.available.values()
]
>>> [c.MARKER for
(t, c) in pool.available
]
[1, 2, 3]
[1, 2, 3]
Similarly for the other two:
Similarly for the other two:
...
@@ -252,7 +252,7 @@ Similarly for the other two:
...
@@ -252,7 +252,7 @@ Similarly for the other two:
>>> conns[1].close(); conns[2].close()
>>> conns[1].close(); conns[2].close()
>>> len(pool.available), len(pool.all)
>>> len(pool.available), len(pool.all)
(3, 3)
(3, 3)
>>> [c.MARKER for
c in pool.available.values()
]
>>> [c.MARKER for
(t, c) in pool.available
]
[3, 4, 5]
[3, 4, 5]
Reducing the pool size may also purge the oldest closed connections:
Reducing the pool size may also purge the oldest closed connections:
...
@@ -260,7 +260,7 @@ Reducing the pool size may also purge the oldest closed connections:
...
@@ -260,7 +260,7 @@ Reducing the pool size may also purge the oldest closed connections:
>>> db.setPoolSize(2) # gets rid of MARKER 3
>>> db.setPoolSize(2) # gets rid of MARKER 3
>>> len(pool.available), len(pool.all)
>>> len(pool.available), len(pool.all)
(2, 2)
(2, 2)
>>> [c.MARKER for
c in pool.available.values()
]
>>> [c.MARKER for
(t, c) in pool.available
]
[4, 5]
[4, 5]
Since MARKER 5 is still the last one added to the stack, it will be the
Since MARKER 5 is still the last one added to the stack, it will be the
...
...
src/ZODB/tests/testhistoricalconnections.py
View file @
c028ea24
...
@@ -25,10 +25,7 @@ def setUp(test):
...
@@ -25,10 +25,7 @@ def setUp(test):
def
tearDown
(
test
):
def
tearDown
(
test
):
test
.
globs
[
'db'
].
close
()
test
.
globs
[
'db'
].
close
()
test
.
globs
[
'db2'
].
close
()
test
.
globs
[
'db2'
].
close
()
test
.
globs
[
'storage'
].
close
()
# the DB class masks the module because of __init__ shenanigans
# the DB class masks the module because of __init__ shenanigans
DB_module
=
__import__
(
'ZODB.DB'
,
globals
(),
locals
(),
[
'chicken'
])
DB_module
.
time
=
test
.
globs
[
'original_time'
]
module
.
tearDown
(
test
)
module
.
tearDown
(
test
)
ZODB
.
tests
.
util
.
tearDown
(
test
)
ZODB
.
tests
.
util
.
tearDown
(
test
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment