From ce258cd00b2c8e0d16be79a5c8ffe0572fae1a2c Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 6 May 2020 02:59:41 -0700 Subject: [PATCH] Cache tool work --- .efrocachemap | 24 +++++------ .idea/dictionaries/ericf.xml | 2 + tools/efrotools/efrocache.py | 28 ++++++++---- tools/staging_server_upkeep | 82 ++++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 20 deletions(-) create mode 100755 tools/staging_server_upkeep diff --git a/.efrocachemap b/.efrocachemap index 57ab8ece..db8cd596 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6a/56/e48e9306428b4ae7b58225fce76c", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/dd/2d/bdd22cbd39a9bb27a75302ef837a", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/61/f2/a679c5a3c9113c7b7599a59415fb", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6c/21/c80e03031e6c5959140588d439bf", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/42/ff/6d9056500a768dae79ed44180796", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/58/d4/3f6d3cb75988db046f22bfb5c2a5", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a8/07/edf6360c8e5b824633bf55c97ed9", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/27/cc/0ec7cab492f111923320dc165427", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b2/b4/f68901c3dae4267a5640bf702d86", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ae/b7/0400bd1021d0fc0c40d1c2149364", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ee/6e/8f88fef729d85a07910cbedbac31", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e1/90/4877825fb2d779bd7ac9704a1a4c" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8b/e2/8ab3f02c813d2e43df787d478023", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ca/46/ae21c3d6765f6625ac06b9215f3d", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/21/f2/079c550e8ba0e255c6255dc0737a", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/19/f3/1121125a99e5efb3577a491799e9", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/87/b1/4d076556aac39f44ccb03278f584", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/84/f6/607fd2ab859f610fdd91a9a857db", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/40/f3/00df4a55512b824534bda6945204", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f8/2f/09295de6690e6df09c0003b4d85b", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/61/62/2e8398b3dcf1ae702ba591aa947e", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e1/db/1acefefb21e4fd0fe8e337647592", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ef/85/b8235ca82f2e3319850535558f0f", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/26/ba/1f40445d853e6be53beacd7a3ca3" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index b847cba0..7dea5109 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -17,6 +17,7 @@ abeb abot abtn + accesstime accountname accountui accum @@ -687,6 +688,7 @@ fsplit fsrc fstab + fstat fstrs ftime ftmp diff --git a/tools/efrotools/efrocache.py b/tools/efrotools/efrocache.py index 73ef3dd2..5f8b8542 100644 --- a/tools/efrotools/efrocache.py +++ b/tools/efrotools/efrocache.py @@ -284,8 +284,9 @@ def _gen_hashes(fnames: List[str]) -> str: def _write_cache_files(fnames1: List[str], fnames2: List[str], staging_dir: str, mapping_file: str) -> None: - fhashes1: Set[str] = set() import functools + fhashes1: Set[str] = set() + fhashes2: Set[str] = set() mapping: Dict[str, str] = {} call = functools.partial(_write_cache_file, staging_dir) @@ -296,21 +297,38 @@ def _write_cache_files(fnames1: List[str], fnames2: List[str], mapping[result[0]] = BASE_URL + result[1] fhashes1.add(result[1]) + # Now finish up with the second set. + with ThreadPoolExecutor(max_workers=cpu_count()) as executor: + results = executor.map(call, fnames2) + for result in results: + mapping[result[0]] = BASE_URL + result[1] + fhashes2.add(result[1]) + # We want the server to have a startercache.tar.xz file which contains - # this entire first set. It is much more efficient to build that file + # the entire first set. It is much more efficient to build that file # on the server than it is to build it here and upload the whole thing. # ...so let's simply write a script to generate it and upload that. + # Also let's have the script touch both sets of files so we can use + # mod-times to prune older files. (otherwise files that never change + # might have very old mod times) script = ( 'import os\n' + 'import pathlib\n' 'import subprocess\n' 'fnames = ' + repr(fhashes1) + '\n' + 'fnames2 = ' + repr(fhashes2) + '\n' 'subprocess.run(["rm", "-rf", "efrocache"], check=True)\n' 'print("Copying starter cache files...", flush=True)\n' 'for fname in fnames:\n' ' dst = os.path.join("efrocache", fname)\n' ' os.makedirs(os.path.dirname(dst), exist_ok=True)\n' ' subprocess.run(["cp", fname, dst], check=True)\n' + 'print("Touching full file set...", flush=True)\n' + 'for fname in list(fnames) + list(fnames2):\n' + ' fpath = pathlib.Path(fname)\n' + ' assert fpath.exists()\n' + ' fpath.touch()\n' 'print("Compressing starter cache archive...", flush=True)\n' 'subprocess.run(["tar", "-Jcf", "tmp.tar.xz", "efrocache"],' ' check=True)\n' @@ -322,12 +340,6 @@ def _write_cache_files(fnames1: List[str], fnames2: List[str], with open('build/efrocache/genstartercache.py', 'w') as outfile: outfile.write(script) - # Now finish up with the second set. - with ThreadPoolExecutor(max_workers=cpu_count()) as executor: - results = executor.map(call, fnames2) - for result in results: - mapping[result[0]] = BASE_URL + result[1] - with open(mapping_file, 'w') as outfile: outfile.write(json.dumps(mapping, indent=2, sort_keys=True)) diff --git a/tools/staging_server_upkeep b/tools/staging_server_upkeep new file mode 100755 index 00000000..8ab000da --- /dev/null +++ b/tools/staging_server_upkeep @@ -0,0 +1,82 @@ +#!/usr/bin/env python3.7 +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Perform various tidying on the staging server.""" + +from __future__ import annotations + +import sys +import os +import subprocess +import stat +from pathlib import Path +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + pass + + +def run() -> None: + """Do the thing.""" + rootdir = 'files.ballistica.net/cache/ba1' + assert os.path.isdir(rootdir) + + # Just make a temp file to get 'now'. + # (ugly but effective) + tmppath = Path('_tmp_time_test') + tmppath.touch() + curtime = tmppath.stat()[stat.ST_ATIME] + tmppath.unlink() + + oldest_age = 0 + + for root, _dirnames, fnames in os.walk(rootdir): + for fname in fnames: + # print('doing', os.path.join(root, fname)) + fstat = os.stat(os.path.join(root, fname)) + accesstime = fstat[stat.ST_MTIME] + age = curtime - accesstime + oldest_age = max(oldest_age, age) + # print('was', (curtime - accesstime)/60, 'min') + # print('TEMP BREW') + # break + print('oldest is', oldest_age / 60 / 60 // 24, 'day') + + +def remote_run() -> None: + """Upload and execute ourself.""" + + print(f'Uploading {__file__}...') + subprocess.run(['rsync', __file__, 'ubuntu@ballistica.net:'], check=True) + + subprocess.run([ + 'ssh', 'ubuntu@ballistica.net', + './staging_server_upkeep -run && rm staging_server_upkeep' + ], + check=True) + print('SUCCESS') + + +if __name__ == '__main__': + if '-run' in sys.argv: + run() + else: + remote_run()