Fixed #21621 -- Removed kqueue autoreloader.

This commit is contained in:
Aymeric Augustin 2013-12-15 14:42:58 +01:00
parent dfc95d240d
commit 3beffea4b0
2 changed files with 4 additions and 107 deletions

View File

@ -33,7 +33,6 @@ from __future__ import absolute_import # Avoid importing `importlib` from this
import os import os
import signal import signal
import sys import sys
import tempfile
import time import time
import traceback import traceback
@ -41,7 +40,6 @@ from django.conf import settings
from django.core.signals import request_finished from django.core.signals import request_finished
from django.utils._os import upath from django.utils._os import upath
from importlib import import_module from importlib import import_module
from django.utils import six
try: try:
from django.utils.six.moves import _thread as thread from django.utils.six.moves import _thread as thread
except ImportError: except ImportError:
@ -71,20 +69,6 @@ try:
except ImportError: except ImportError:
pass pass
try:
import select
select.kevent, select.kqueue
USE_KQUEUE = True
import resource
NOFILES_SOFT, NOFILES_HARD = resource.getrlimit(resource.RLIMIT_NOFILE)
import subprocess
command = ["sysctl", "-n", "kern.maxfilesperproc"]
NOFILES_KERN = int(subprocess.check_output(command).strip())
except Exception:
USE_KQUEUE = False
RUN_RELOADER = True RUN_RELOADER = True
_mtimes = {} _mtimes = {}
@ -163,88 +147,6 @@ def inotify_code_changed():
return True return True
def kqueue_code_changed():
"""
Checks for changed code using kqueue. After being called
it blocks until a change event has been fired.
"""
kqueue = select.kqueue()
# Utility function to create kevents.
_filter = select.KQ_FILTER_VNODE
flags = select.KQ_EV_ADD | select.KQ_EV_CLEAR
fflags = select.KQ_NOTE_DELETE | select.KQ_NOTE_WRITE | select.KQ_NOTE_RENAME
def make_kevent(descriptor):
return select.kevent(descriptor, _filter, flags, fflags)
# New modules may get imported when a request is processed. We add a file
# descriptor to the kqueue to exit the kqueue.control after each request.
buf_kwargs = {'buffering' if six.PY3 else 'bufsize': 0}
watcher = tempfile.TemporaryFile(**buf_kwargs)
kqueue.control([make_kevent(watcher)], 0)
def update_watch(sender=None, **kwargs):
watcher.write(b'.')
request_finished.connect(update_watch)
# We have to manage a set of descriptors to avoid the overhead of opening
# and closing every files whenever we reload the set of files to watch.
filenames = set()
descriptors = set()
while True:
old_filenames = filenames
filenames = set(gen_filenames())
new_filenames = filenames - old_filenames
# If new files were added since the last time we went through the loop,
# add them to the kqueue.
if new_filenames:
# We must increase the maximum number of open file descriptors
# because each kevent uses one file descriptor and resource limits
# are too low by default.
#
# In fact there are two limits:
# - kernel limit: `sysctl kern.maxfilesperproc` -> 10240 on OS X.9
# - resource limit: `launchctl limit maxfiles` -> 256 on OS X.9
#
# The latter can be changed with Python's resource module, but it
# can never exceed the former. Unfortunately, getrlimit(3) -- used
# by both launchctl and the resource module -- reports no "hard
# limit", even though the kernel sets one.
# If project is too large or kernel limits are too tight, use polling.
if len(filenames) >= NOFILES_KERN:
return code_changed()
# Add the number of file descriptors we're going to use to the current
# resource limit, while staying within the kernel limit.
nofiles_target = min(len(filenames) + NOFILES_SOFT, NOFILES_KERN)
resource.setrlimit(resource.RLIMIT_NOFILE, (nofiles_target, NOFILES_HARD))
new_descriptors = set(open(filename) for filename in new_filenames)
descriptors |= new_descriptors
kqueue.control([make_kevent(descriptor) for descriptor in new_descriptors], 0)
events = kqueue.control([], 1)
# After a request, reload the set of watched files.
if len(events) == 1 and events[0].ident == watcher.fileno():
continue
# If the change affected another file, clean up and exit.
for descriptor in descriptors:
descriptor.close()
watcher.close()
kqueue.close()
return True
def code_changed(): def code_changed():
global _mtimes, _win global _mtimes, _win
for filename in gen_filenames(): for filename in gen_filenames():
@ -307,8 +209,6 @@ def reloader_thread():
ensure_echo_on() ensure_echo_on()
if USE_INOTIFY: if USE_INOTIFY:
fn = inotify_code_changed fn = inotify_code_changed
elif USE_KQUEUE:
fn = kqueue_code_changed
else: else:
fn = code_changed fn = code_changed
while RUN_RELOADER: while RUN_RELOADER:

View File

@ -398,13 +398,10 @@ Management Commands
* The :djadmin:`runserver` command received several improvements: * The :djadmin:`runserver` command received several improvements:
* On BSD systems, including OS X, the development server will reload * On Linux systems, if pyinotify_ is installed, the development server will
immediately when a file is changed. Previously, it polled the filesystem reload immediately when a file is changed. Previously, it polled the
for changes every second. That caused a small delay before reloads and filesystem for changes every second. That caused a small delay before
reduced battery life on laptops. reloads and reduced battery life on laptops.
* On Linux, the same improvements are available when pyinotify_ is
installed.
.. _pyinotify: https://pypi.python.org/pypi/pyinotify .. _pyinotify: https://pypi.python.org/pypi/pyinotify