<commit_before>#
# Quru Image Server
#
# Document:      util.py
# Date started:  27 Mar 2018
# By:            <NAME>
# Purpose:       Auxiliary server utilities
# Requires:
# Copyright:     Quru Ltd (www.quru.com)
# Licence:
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published
#   by the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see http://www.gnu.org/licenses/
#
# Last Changed:  $Date$ $Rev$ by $Author$
#
# Notable modifications:
# Date       By    Details
# =========  ====  ============================================================
# 27Mar2018  Matt  Code moved here from task_server, refactored other servers
#

import os
import time
from multiprocessing import Process

from imageserver.filesystem_manager import get_abs_path
from imageserver.util import get_computer_hostname


def store_pid(proc_name, pid_val):
    """
    Writes the current process ID to a hidden file in the image server file system.
    Raises an IOError or OSError if the pid file cannot be written.
    """
    pid_dir = os.path.dirname(_get_pidfile_path(proc_name))
    if not os.path.exists(pid_dir):
        os.mkdir(pid_dir)
    with open(_get_pidfile_path(proc_name), 'wt', buffering=0) as f:
        f.write(pid_val)


def get_pid(proc_name):
    """
    Returns the last value written by _store_pid() as a string,
    or an empty string if _store_pid() has not been called before.
    Raises an IOError or OSError if the pid file exists but cannot be read.
    """
    if os.path.exists(_get_pidfile_path(proc_name)):
        with open(_get_pidfile_path(proc_name), 'rt') as f:
            return f.read()
    return ''


def _get_pidfile_path(proc_name):
    """
    Returns a path for a PID file, incorporating the given process name and this
    computer's host name (for the case when multiple servers are sharing the same
    back-end file system).
    """
    return os.path.join(
        get_abs_path('/'),
        '.metadata',
        get_computer_hostname() + '.' + proc_name + '.pid'
    )


def double_fork(process_name, process_function, process_args):
    """
    Forks twice, leaving 'target_function' running as a separate grand-child process.
    This fully detaches the final process from the parent process, avoiding issues
    with the parent having to wait() for the child (or else becoming a zombie process)
    or the parent's controlling terminal (if it has one) being closed. This is better
    explained at: http://www.faqs.org/faqs/unix-faq/programmer/faq/
    """
    def _double_fork():
        p = Process(
            target=process_function,
            name=process_name,<commit_msg>py3 - can't have unbuffered text mode, set text encoding<commit_after>#
# Quru Image Server
#
# Document:      util.py
# Date started:  27 Mar 2018
# By:            <NAME>
# Purpose:       Auxiliary server utilities
# Requires:
# Copyright:     Quru Ltd (www.quru.com)
# Licence:
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published
#   by the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see http://www.gnu.org/licenses/
#
# Last Changed:  $Date$ $Rev$ by $Author$
#
# Notable modifications:
# Date       By    Details
# =========  ====  ============================================================
# 27Mar2018  Matt  Code moved here from task_server, refactored other servers
#

import os
import time
from multiprocessing import Process

from imageserver.filesystem_manager import get_abs_path
from imageserver.util import get_computer_hostname


def store_pid(proc_name, pid_val):
    """
    Writes the current process ID to a hidden file in the image server file system.
    Raises an IOError or OSError if the pid file cannot be written.
    """
    pid_dir = os.path.dirname(_get_pidfile_path(proc_name))
    if not os.path.exists(pid_dir):
        os.mkdir(pid_dir)
    with open(_get_pidfile_path(proc_name), 'wt', encoding='utf8') as f:
        f.write(pid_val)


def get_pid(proc_name):
    """
    Returns the last value written by _store_pid() as a string,
    or an empty string if _store_pid() has not been called before.
    Raises an IOError or OSError if the pid file exists but cannot be read.
    """
    if os.path.exists(_get_pidfile_path(proc_name)):
        with open(_get_pidfile_path(proc_name), 'rt', encoding='utf8') as f:
            return f.read()
    return ''


def _get_pidfile_path(proc_name):
    """
    Returns a path for a PID file, incorporating the given process name and this
    computer's host name (for the case when multiple servers are sharing the same
    back-end file system).
    """
    return os.path.join(
        get_abs_path('/'),
        '.metadata',
        get_computer_hostname() + '.' + proc_name + '.pid'
    )


def double_fork(process_name, process_function, process_args):
    """
    Forks twice, leaving 'target_function' running as a separate grand-child process.
    This fully detaches the final process from the parent process, avoiding issues
    with the parent having to wait() for the child (or else becoming a zombie process)
    or the parent's controlling terminal (if it has one) being closed. This is better
    explained at: http://www.faqs.org/faqs/unix-faq/programmer/faq/
    """
    def _double_fork():
        p = Process(
            target=process_function,
            name=process_name,
{'fraction_non_alphanumeric': 0.10028337531486146, 'fraction_numerical': 0.004722921914357683, 'mean_word_length': 3.2925675675675676, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 6, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '952640', 'n_tokens_mistral': 1877, 'n_tokens_neox': 1810, 'n_words': 722}