Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Add configurable timeout to run db script #1550

Merged
merged 2 commits into from
Apr 17, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add configurable timeout to run db script
  • Loading branch information
jkosh44 committed Apr 17, 2021
commit e034fa1a2fe5423caa9eb3b2ffd803ce097fb733
34 changes: 25 additions & 9 deletions script/testing/util/db_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@
# Class definition for `NoisePageServer` used in JUnit tests.

import os
import time
import shlex
import pathlib
import shlex
import subprocess
import time
from typing import Dict, List

import psycopg2 as psql

from typing import Dict, List

from .common import print_pipe
from .constants import (DEFAULT_DB_BIN, DEFAULT_DB_HOST,
DEFAULT_DB_OUTPUT_FILE, DEFAULT_DB_PORT,
DEFAULT_DB_USER, DEFAULT_DB_WAL_FILE, DIR_REPO, LOG)


# -----------------------------------------------------------------------------
# NoisePageServer

Expand Down Expand Up @@ -53,7 +53,7 @@ def __init__(self, host=DEFAULT_DB_HOST, port=DEFAULT_DB_PORT, build_type='', se
self.db_output_file = db_output_file
self.db_process = None

def run_db(self, is_dry_run=False):
def run_db(self, is_dry_run=False, timeout=600):
"""
Start the DBMS.

Expand All @@ -62,6 +62,9 @@ def run_db(self, is_dry_run=False):
is_dry_run : bool
True if the commands that will be run should be printed,
with the commands themselves not actually executing.
timeout : int
How long to wait, in seconds, for the database to start up
before exiting. Default is 600 seconds.

Returns
-------
Expand Down Expand Up @@ -108,9 +111,9 @@ def run_db(self, is_dry_run=False):
LOG.info("************* DB Logs End *************")
return True

if now - start_time >= 600:
if now - start_time >= timeout:
LOG.error('\n'.join(logs))
LOG.error(f'DBMS [PID={db_process.pid}] took more than 600 seconds to start up. Killing.')
LOG.error(f'DBMS [PID={db_process.pid}] took more than {timeout} seconds to start up. Killing.')
db_process.kill()
return False

Expand Down Expand Up @@ -247,6 +250,7 @@ def execute(self, sql, expect_result=True, quiet=True, user=DEFAULT_DB_USER, aut
LOG.error(f"Executing SQL failed: {sql}")
raise e


# -----------------------------------------------------------------------------
# Server Utilities

Expand Down Expand Up @@ -285,6 +289,7 @@ def get_binary_directory(build_type):

raise RuntimeError(f'No DBMS binary found in: {path_list}')


def construct_server_args_string(server_args, bin_dir):
"""
Construct the arguments string to pass to the DBMS server.
Expand All @@ -306,6 +311,7 @@ def construct_server_args_string(server_args, bin_dir):
# Construct the string DBMS argument string
return " ".join([construct_server_argument(attribute, value, meta) for attribute, value in server_args.items()])


def construct_server_argument(attr, value, meta):
"""
Construct a DBMS server argument from the associated attribute and value.
Expand Down Expand Up @@ -350,10 +356,11 @@ def construct_server_argument(attr, value, meta):
# Make the attribute available to the value preprocessors
value_meta = {**meta, **{"attr": attr}}

preprocessed_attr = apply_all(ATTR_PREPROCESSORS, attr, attr_meta)
preprocessed_attr = apply_all(ATTR_PREPROCESSORS, attr, attr_meta)
preprocessed_value = apply_all(VALUE_PREPROCESSORS, value, value_meta)
return f"-{preprocessed_attr}{preprocessed_value}"


# -----------------------------------------------------------------------------
# Preprocessing Utilities

Expand All @@ -363,9 +370,11 @@ class AllTypes:
that should ALWAYS be applied, regardless of the type of the
value or attribute being processed.
"""

def __init__(self):
pass


def applies_to(*target_types):
"""
A decorator that produces a no-op function in the event that the 'target'
Expand All @@ -376,16 +385,20 @@ def applies_to(*target_types):
as a decorator for preprocessor functions to deal with the fact that
certain preprocessing operations are only applicable to certain types.
"""

def wrap_outer(f):
def wrap_inner(target, meta):
# The argument is a targeted type if the catch-all type AllTypes
# is provided as an argument to the decorator OR the argument is
# an instance of any of the types provided as an argument
arg_is_targeted_type = AllTypes in target_types or any(isinstance(target, ty) for ty in target_types)
return f(target, meta) if arg_is_targeted_type else target

return wrap_inner

return wrap_outer


# -----------------------------------------------------------------------------
# Attribute Preprocessors
#
Expand Down Expand Up @@ -424,6 +437,7 @@ def lower_booleans(value: str, meta: Dict) -> str:
assert value is True or value is False, "Input must be a first-class boolean type."
return str(value).lower()


@applies_to(str)
def resolve_relative_paths(value: str, meta: Dict) -> str:
"""
Expand Down Expand Up @@ -462,12 +476,13 @@ def resolve_relative_paths(value: str, meta: Dict) -> str:
# otherwise be expected, never more.
is_path = str.endswith(meta["attr"], "_path")
is_relative = not os.path.isabs(value)

if is_path and is_relative:
return pathlib.Path(os.path.join(meta["bin_dir"], value)).resolve()
else:
return value


@applies_to(AllTypes)
def handle_flags(value: str, meta: Dict) -> str:
"""
Expand All @@ -494,6 +509,7 @@ def handle_flags(value: str, meta: Dict) -> str:
"""
return f"={value}" if value is not None else ""


# -----------------------------------------------------------------------------
# Utility

Expand Down