Skip to content

Commit c3d6a76

Browse files
committed
Use a lock directory to prevent race condition
...when creating the font cache
1 parent 8000e2f commit c3d6a76

File tree

3 files changed

+110
-5
lines changed

3 files changed

+110
-5
lines changed

LICENSE/LICENSE_CONDA

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
Except where noted below, conda is released under the following terms:
2+
3+
(c) 2012 Continuum Analytics, Inc. / http://continuum.io
4+
All Rights Reserved
5+
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions are met:
8+
* Redistributions of source code must retain the above copyright
9+
notice, this list of conditions and the following disclaimer.
10+
* Redistributions in binary form must reproduce the above copyright
11+
notice, this list of conditions and the following disclaimer in the
12+
documentation and/or other materials provided with the distribution.
13+
* Neither the name of Continuum Analytics, Inc. nor the
14+
names of its contributors may be used to endorse or promote products
15+
derived from this software without specific prior written permission.
16+
17+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20+
DISCLAIMED. IN NO EVENT SHALL CONTINUUM ANALYTICS BE LIABLE FOR ANY
21+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27+
28+
29+
Exceptions
30+
==========
31+
32+
versioneer.py is Public Domain
33+
34+
The ProgressBar package is released under the following terms:
35+
36+
# progressbar - Text progress bar library for Python.
37+
# Copyright (c) 2005 Nilton Volpato
38+
#
39+
# This library is free software; you can redistribute it and/or
40+
# modify it under the terms of the GNU Lesser General Public
41+
# License as published by the Free Software Foundation; either
42+
# version 2.1 of the License, or (at your option) any later version.
43+
#
44+
# This library is distributed in the hope that it will be useful,
45+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
46+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
47+
# Lesser General Public License for more details.
48+
#
49+
# You should have received a copy of the GNU Lesser General Public
50+
# License along with this library; if not, write to the Free Software
51+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

lib/matplotlib/cbook.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2550,3 +2550,54 @@ def get_label(y, default_name):
25502550
else:
25512551
def _putmask(a, mask, values):
25522552
return np.copyto(a, values, where=mask)
2553+
2554+
2555+
class Locked(object):
2556+
"""
2557+
Context manager to handle locks.
2558+
2559+
Based on code from conda.
2560+
2561+
(c) 2012-2013 Continuum Analytics, Inc. / http://continuum.io
2562+
All Rights Reserved
2563+
2564+
conda is distributed under the terms of the BSD 3-clause license.
2565+
Consult LICENSE.txt or http://opensource.org/licenses/BSD-3-Clause.
2566+
"""
2567+
def __init__(self, path):
2568+
LOCKFN = '.matplotlib_lock'
2569+
self.path = path
2570+
self.end = "-" + str(os.getpid())
2571+
self.lock_path = os.path.join(self.path, LOCKFN + self.end)
2572+
self.pattern = os.path.join(self.path, LOCKFN + '-*')
2573+
self.remove = True
2574+
2575+
def __enter__(self):
2576+
retries = 10
2577+
sleeptime = 1
2578+
while retries:
2579+
files = glob.glob(self.pattern)
2580+
if files and not files[0].endswith(self.end):
2581+
time.sleep(sleeptime)
2582+
sleeptime *= 2
2583+
retries -= 1
2584+
else:
2585+
break
2586+
else:
2587+
raise RuntimeError(lockstr)
2588+
2589+
if not files:
2590+
try:
2591+
os.makedirs(self.lock_path)
2592+
except OSError:
2593+
pass
2594+
else: # PID lock already here --- someone else will remove it.
2595+
self.remove = False
2596+
2597+
def __exit__(self, exc_type, exc_value, traceback):
2598+
if self.remove:
2599+
for path in self.lock_path, self.path:
2600+
try:
2601+
os.rmdir(path)
2602+
except OSError:
2603+
pass

lib/matplotlib/font_manager.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,10 +1405,9 @@ def findfont(prop, fontext='ttf'):
14051405
else:
14061406
_fmcache = None
14071407

1408-
if not 'TRAVIS' in os.environ:
1409-
cachedir = get_cachedir()
1410-
if cachedir is not None:
1411-
_fmcache = os.path.join(cachedir, 'fontList.json')
1408+
cachedir = get_cachedir()
1409+
if cachedir is not None:
1410+
_fmcache = os.path.join(cachedir, 'fontList.json')
14121411

14131412
fontManager = None
14141413

@@ -1419,9 +1418,13 @@ def findfont(prop, fontext='ttf'):
14191418

14201419
def _rebuild():
14211420
global fontManager
1421+
14221422
fontManager = FontManager()
1423+
14231424
if _fmcache:
1424-
json_dump(fontManager, _fmcache)
1425+
with cbook.Locked(cachedir):
1426+
json_dump(fontManager, _fmcache)
1427+
14251428
verbose.report("generated new fontManager")
14261429

14271430
if _fmcache:

0 commit comments

Comments
 (0)