Skip to content

Commit bbbec3e

Browse files
NodeApp is refactored (#278)
This patch contains a lot of improvements for NodeApp. Fixes and changes: - NodeApp was moved to own py-file - NodeApp::os_ops is RO-property - NodeApp::test_path is RO-property - NodeApp::nodes_to_cleanup is RO-property - NodeApp supports an external port manager object - NodeApp.make_simple changes input parameter initdb_params #267 - NodeApp::make_empty has a problem with base_dir = None #277 - NodeApp.make_empty must pass os_ops and port_manager to nodes #265 Also - OsOperations::create_clone is added - PostgresNode::release_resources is added
1 parent 69f8d49 commit bbbec3e

File tree

8 files changed

+670
-189
lines changed

8 files changed

+670
-189
lines changed

testgres/__init__.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@
3333
ProcessType, \
3434
DumpFormat
3535

36-
from .node import PostgresNode, NodeApp
36+
from .node import PostgresNode
3737
from .node import PortManager
38+
from .node_app import NodeApp
3839

3940
from .utils import \
4041
reserve_port, \
@@ -62,8 +63,9 @@
6263
"NodeConnection", "DatabaseError", "InternalError", "ProgrammingError", "OperationalError",
6364
"TestgresException", "ExecUtilException", "QueryException", "TimeoutException", "CatchUpException", "StartNodeException", "InitNodeException", "BackupException", "InvalidOperationException",
6465
"XLogMethod", "IsolationLevel", "NodeStatus", "ProcessType", "DumpFormat",
65-
"PostgresNode", "NodeApp",
66-
"PortManager",
66+
NodeApp.__name__,
67+
PostgresNode.__name__,
68+
PortManager.__name__,
6769
"reserve_port", "release_port", "bound_ports", "get_bin_path", "get_pg_config", "get_pg_version",
6870
"First", "Any",
6971
"OsOperations", "LocalOperations", "RemoteOperations", "ConnectionParams"

testgres/node.py

Lines changed: 26 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
import signal
88
import subprocess
99
import threading
10-
import tempfile
11-
import platform
1210
from queue import Queue
1311

1412
import time
@@ -692,9 +690,6 @@ def _try_shutdown(self, max_attempts, with_force=False):
692690
ps_output,
693691
ps_command)
694692

695-
def _release_resources(self):
696-
self.free_port()
697-
698693
@staticmethod
699694
def _throw_bugcheck__unexpected_result_of_ps(result, cmd):
700695
assert type(result) == str # noqa: E721
@@ -1326,25 +1321,18 @@ def pg_ctl(self, params):
13261321

13271322
return execute_utility2(self.os_ops, _params, self.utils_log_file)
13281323

1324+
def release_resources(self):
1325+
"""
1326+
Release resorces owned by this node.
1327+
"""
1328+
return self._release_resources()
1329+
13291330
def free_port(self):
13301331
"""
13311332
Reclaim port owned by this node.
13321333
NOTE: this method does not release manually defined port but reset it.
13331334
"""
1334-
assert type(self._should_free_port) == bool # noqa: E721
1335-
1336-
if not self._should_free_port:
1337-
self._port = None
1338-
else:
1339-
assert type(self._port) == int # noqa: E721
1340-
1341-
assert self._port_manager is not None
1342-
assert isinstance(self._port_manager, PortManager)
1343-
1344-
port = self._port
1345-
self._should_free_port = False
1346-
self._port = None
1347-
self._port_manager.release_port(port)
1335+
return self._free_port()
13481336

13491337
def cleanup(self, max_attempts=3, full=False, release_resources=False):
13501338
"""
@@ -2158,6 +2146,25 @@ def upgrade_from(self, old_node, options=None, expect_error=False):
21582146

21592147
return self.os_ops.exec_command(upgrade_command, expect_error=expect_error)
21602148

2149+
def _release_resources(self):
2150+
self._free_port()
2151+
2152+
def _free_port(self):
2153+
assert type(self._should_free_port) == bool # noqa: E721
2154+
2155+
if not self._should_free_port:
2156+
self._port = None
2157+
else:
2158+
assert type(self._port) == int # noqa: E721
2159+
2160+
assert self._port_manager is not None
2161+
assert isinstance(self._port_manager, PortManager)
2162+
2163+
port = self._port
2164+
self._should_free_port = False
2165+
self._port = None
2166+
self._port_manager.release_port(port)
2167+
21612168
def _get_bin_path(self, filename):
21622169
assert self._os_ops is not None
21632170
assert isinstance(self._os_ops, OsOperations)
@@ -2352,164 +2359,3 @@ def delect_port_conflict(log_reader: PostgresNodeLogReader) -> bool:
23522359
return True
23532360

23542361
return False
2355-
2356-
2357-
class NodeApp:
2358-
2359-
def __init__(self, test_path=None, nodes_to_cleanup=None, os_ops=None):
2360-
assert os_ops is None or isinstance(os_ops, OsOperations)
2361-
2362-
if os_ops is None:
2363-
os_ops = LocalOperations.get_single_instance()
2364-
2365-
assert isinstance(os_ops, OsOperations)
2366-
2367-
if test_path:
2368-
if os.path.isabs(test_path):
2369-
self.test_path = test_path
2370-
else:
2371-
self.test_path = os_ops.build_path(os_ops.cwd(), test_path)
2372-
else:
2373-
self.test_path = os_ops.cwd()
2374-
self.nodes_to_cleanup = nodes_to_cleanup if nodes_to_cleanup else []
2375-
self.os_ops = os_ops
2376-
2377-
def make_empty(
2378-
self,
2379-
base_dir=None,
2380-
port=None,
2381-
bin_dir=None):
2382-
real_base_dir = self.os_ops.build_path(self.test_path, base_dir)
2383-
self.os_ops.rmdirs(real_base_dir, ignore_errors=True)
2384-
self.os_ops.makedirs(real_base_dir)
2385-
2386-
node = PostgresNode(base_dir=real_base_dir, port=port, bin_dir=bin_dir)
2387-
self.nodes_to_cleanup.append(node)
2388-
2389-
return node
2390-
2391-
def make_simple(
2392-
self,
2393-
base_dir=None,
2394-
port=None,
2395-
set_replication=False,
2396-
ptrack_enable=False,
2397-
initdb_params=[],
2398-
pg_options={},
2399-
checksum=True,
2400-
bin_dir=None):
2401-
assert type(pg_options) == dict # noqa: E721
2402-
2403-
if checksum and '--data-checksums' not in initdb_params:
2404-
initdb_params.append('--data-checksums')
2405-
node = self.make_empty(base_dir, port, bin_dir=bin_dir)
2406-
node.init(
2407-
initdb_params=initdb_params, allow_streaming=set_replication)
2408-
2409-
# set major version
2410-
pg_version_file = self.os_ops.read(self.os_ops.build_path(node.data_dir, 'PG_VERSION'))
2411-
node.major_version_str = str(pg_version_file.rstrip())
2412-
node.major_version = float(node.major_version_str)
2413-
2414-
# Set default parameters
2415-
options = {
2416-
'max_connections': 100,
2417-
'shared_buffers': '10MB',
2418-
'fsync': 'off',
2419-
'wal_level': 'logical',
2420-
'hot_standby': 'off',
2421-
'log_line_prefix': '%t [%p]: [%l-1] ',
2422-
'log_statement': 'none',
2423-
'log_duration': 'on',
2424-
'log_min_duration_statement': 0,
2425-
'log_connections': 'on',
2426-
'log_disconnections': 'on',
2427-
'restart_after_crash': 'off',
2428-
'autovacuum': 'off',
2429-
# unix_socket_directories will be defined later
2430-
}
2431-
2432-
# Allow replication in pg_hba.conf
2433-
if set_replication:
2434-
options['max_wal_senders'] = 10
2435-
2436-
if ptrack_enable:
2437-
options['ptrack.map_size'] = '1'
2438-
options['shared_preload_libraries'] = 'ptrack'
2439-
2440-
if node.major_version >= 13:
2441-
options['wal_keep_size'] = '200MB'
2442-
else:
2443-
options['wal_keep_segments'] = '12'
2444-
2445-
# Apply given parameters
2446-
for option_name, option_value in iteritems(pg_options):
2447-
options[option_name] = option_value
2448-
2449-
# Define delayed propertyes
2450-
if not ("unix_socket_directories" in options.keys()):
2451-
options["unix_socket_directories"] = __class__._gettempdir_for_socket()
2452-
2453-
# Set config values
2454-
node.set_auto_conf(options)
2455-
2456-
# kludge for testgres
2457-
# https://github.com/postgrespro/testgres/issues/54
2458-
# for PG >= 13 remove 'wal_keep_segments' parameter
2459-
if node.major_version >= 13:
2460-
node.set_auto_conf({}, 'postgresql.conf', ['wal_keep_segments'])
2461-
2462-
return node
2463-
2464-
@staticmethod
2465-
def _gettempdir_for_socket():
2466-
platform_system_name = platform.system().lower()
2467-
2468-
if platform_system_name == "windows":
2469-
return __class__._gettempdir()
2470-
2471-
#
2472-
# [2025-02-17] Hot fix.
2473-
#
2474-
# Let's use hard coded path as Postgres likes.
2475-
#
2476-
# pg_config_manual.h:
2477-
#
2478-
# #ifndef WIN32
2479-
# #define DEFAULT_PGSOCKET_DIR "/tmp"
2480-
# #else
2481-
# #define DEFAULT_PGSOCKET_DIR ""
2482-
# #endif
2483-
#
2484-
# On the altlinux-10 tempfile.gettempdir() may return
2485-
# the path to "private" temp directiry - "/temp/.private/<username>/"
2486-
#
2487-
# But Postgres want to find a socket file in "/tmp" (see above).
2488-
#
2489-
2490-
return "/tmp"
2491-
2492-
@staticmethod
2493-
def _gettempdir():
2494-
v = tempfile.gettempdir()
2495-
2496-
#
2497-
# Paranoid checks
2498-
#
2499-
if type(v) != str: # noqa: E721
2500-
__class__._raise_bugcheck("tempfile.gettempdir returned a value with type {0}.".format(type(v).__name__))
2501-
2502-
if v == "":
2503-
__class__._raise_bugcheck("tempfile.gettempdir returned an empty string.")
2504-
2505-
if not os.path.exists(v):
2506-
__class__._raise_bugcheck("tempfile.gettempdir returned a not exist path [{0}].".format(v))
2507-
2508-
# OK
2509-
return v
2510-
2511-
@staticmethod
2512-
def _raise_bugcheck(msg):
2513-
assert type(msg) == str # noqa: E721
2514-
assert msg != ""
2515-
raise Exception("[BUG CHECK] " + msg)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy