Bug 1251870 - Disable indexing of objdir on Windows; r?ted draft
authorGregory Szorc <gps@mozilla.com>
Sat, 27 Feb 2016 11:58:12 -0800
changeset 335164 860e051102e1dddcb95776f3f6593f6e59557f0b
parent 335075 5e0140b6d11821e0c2a2de25bc5431783f03380a
child 335167 b6376d19a819ac91ba583fd5a1146601b5051af8
push id11741
push usergszorc@mozilla.com
push dateSat, 27 Feb 2016 19:58:21 +0000
reviewersted
bugs1251870
milestone47.0a1
Bug 1251870 - Disable indexing of objdir on Windows; r?ted The Windows content indexing service has been known to scan the objdir. This can add significant system overhead and slow down builds or subsequent operations. The objdir is meant to be a short-lived black box and there really isn't a major benefit to indexing it. There is a file attribute on Windows that disables content indexing. This commit adds a utility function for creating a directory and optionally disabling indexing on it. We call it at the top of `mach build` to ensure the objdir as content indexing disabled. MozReview-Commit-ID: 68gxCxbkVAN
python/mozbuild/mozbuild/mach_commands.py
python/mozbuild/mozbuild/util.py
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -300,25 +300,32 @@ class Build(MachCommandBase):
         * faster - builds JavaScript, XUL, CSS, etc files.
 
         "binaries" and "faster" almost fully complement each other. However,
         there are build actions not captured by either. If things don't appear to
         be rebuilding, perform a vanilla `mach build` to rebuild the world.
         """
         import which
         from mozbuild.controller.building import BuildMonitor
-        from mozbuild.util import resolve_target_to_make
+        from mozbuild.util import (
+            mkdir,
+            resolve_target_to_make,
+        )
 
         self.log_manager.register_structured_logger(logging.getLogger('mozbuild'))
 
         warnings_path = self._get_state_filename('warnings.json')
         monitor = self._spawn(BuildMonitor)
         monitor.init(warnings_path)
         ccache_start = monitor.ccache_stats()
 
+        # Disable indexing in objdir because it is not necessary and can slow
+        # down builds.
+        mkdir(self.topobjdir, not_indexed=True)
+
         with BuildOutputManager(self.log_manager, monitor) as output:
             monitor.start()
 
             if directory is not None and not what:
                 print('Can only use -C/--directory with an explicit target '
                     'name.')
                 return 1
 
--- a/python/mozbuild/mozbuild/util.py
+++ b/python/mozbuild/mozbuild/util.py
@@ -4,16 +4,17 @@
 
 # This file contains miscellaneous utility functions that don't belong anywhere
 # in particular.
 
 from __future__ import absolute_import, unicode_literals
 
 import argparse
 import collections
+import ctypes
 import difflib
 import errno
 import functools
 import hashlib
 import itertools
 import os
 import re
 import stat
@@ -31,16 +32,21 @@ from io import (
 )
 
 
 if sys.version_info[0] == 3:
     str_type = str
 else:
     str_type = basestring
 
+if sys.platform == 'win32':
+    _kernel32 = ctypes.windll.kernel32
+    _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
+
+
 def hash_file(path, hasher=None):
     """Hashes a file specified by the path given and returns the hex digest."""
 
     # If the default hashing function changes, this may invalidate
     # lots of cached data.  Don't change it lightly.
     h = hasher or hashlib.sha1()
 
     with open(path, 'rb') as fh:
@@ -106,16 +112,38 @@ def ensureParentDir(path):
     if d and not os.path.exists(path):
         try:
             os.makedirs(d)
         except OSError, error:
             if error.errno != errno.EEXIST:
                 raise
 
 
+def mkdir(path, not_indexed=False):
+    """Ensure a directory exists.
+
+    If ``not_indexed`` is True, an attribute is set that disables content
+    indexing on the directory.
+    """
+    try:
+        os.makedirs(path)
+    except OSError as e:
+        if e.errno != errno.EEXIST:
+            raise
+
+    if not_indexed:
+        if sys.platform == 'win32':
+            if isinstance(path, str_type):
+                fn = _kernel32.SetFileAttributesW
+            else:
+                fn = _kernel32.SetFileAttributesA
+
+            fn(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
+
+
 def simple_diff(filename, old_lines, new_lines):
     """Returns the diff between old_lines and new_lines, in unified diff form,
     as a list of lines.
 
     old_lines and new_lines are lists of non-newline terminated lines to
     compare.
     old_lines can be None, indicating a file creation.
     new_lines can be None, indicating a file deletion.