Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8c96ba0

Browse files
committed
small fixes and refactoring after a chat with@ildus
1 parent91a56e8 commit8c96ba0

File tree

5 files changed

+198
-161
lines changed

5 files changed

+198
-161
lines changed

‎run_tests.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ time coverage run -a tests/test_simple.py
4747
unset PG_BIN
4848

4949

50-
# run tests (PG_CONFIG), also without psutil
51-
$PIP uninstall -y psutil
50+
# run tests (PG_CONFIG)
5251
export PG_CONFIG=$(which pg_config)
5352
time coverage run -a tests/test_simple.py
5453
unset PG_CONFIG

‎testgres/connection.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ def __init__(self, node, dbname=None, username=None, password=None):
3434
username=usernameordefault_username()
3535

3636
self._node=node
37-
self._pid=0
3837

3938
self._connection=pglib.connect(
4039
database=dbname,
@@ -55,9 +54,7 @@ def connection(self):
5554

5655
@property
5756
defpid(self):
58-
ifnotself._pid:
59-
self._pid=self.execute("select pg_backend_pid();")[0][0]
60-
returnself._pid
57+
returnself.execute("select pg_backend_pid()")[0][0]
6158

6259
@property
6360
defcursor(self):

‎testgres/enums.py

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
fromenumimportEnum,IntEnum
2+
fromsiximportiteritems
23

34

45
classXLogMethod(Enum):
@@ -39,14 +40,48 @@ def __bool__(self):
3940

4041
classProcessType(Enum):
4142
"""
42-
Types of postgres processes
43-
"""
44-
Checkpointer='postgres: checkpointer'
45-
BackgroundWriter='postgres: background writer'
46-
WalWriter='postgres: walwriter'
47-
AutovacuumLauncher='postgres: autovacuum launcher'
48-
StatsCollector='postgres: stats collector'
49-
LogicalReplicationLauncher='postgres: logical replication launcher'
50-
WalReceiver='postgres: walreceiver'
51-
WalSender='postgres: walsender'
52-
Startup='postgres: startup'
43+
Types of processes
44+
"""
45+
46+
AutovacuumLauncher='autovacuum launcher'
47+
BackgroundWriter='background writer'
48+
Checkpointer='checkpointer'
49+
LogicalReplicationLauncher='logical replication launcher'
50+
Startup='startup'
51+
StatsCollector='stats collector'
52+
WalReceiver='wal receiver'
53+
WalSender='wal sender'
54+
WalWriter='wal writer'
55+
56+
# special value
57+
Unknown='unknown'
58+
59+
@staticmethod
60+
deffrom_process(process):
61+
# legacy names for older releases of PG
62+
alternative_names= {
63+
ProcessType.LogicalReplicationLauncher: [
64+
'logical replication worker'
65+
],
66+
ProcessType.BackgroundWriter: [
67+
'writer'
68+
],
69+
}
70+
71+
# we deliberately cut special words and spaces
72+
cmdline=''.join(process.cmdline()) \
73+
.replace('postgres:','',1) \
74+
.replace('bgworker:','',1) \
75+
.replace(' ','')
76+
77+
forptypeinProcessType:
78+
ifcmdline.startswith(ptype.value.replace(' ','')):
79+
returnptype
80+
81+
forptype,namesiniteritems(alternative_names):
82+
fornameinnames:
83+
ifcmdline.startswith(name.replace(' ','')):
84+
returnptype
85+
86+
# default
87+
returnProcessType.Unknown

‎testgres/node.py

Lines changed: 103 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,11 @@
22

33
importio
44
importos
5-
importsix
65
importsubprocess
76
importtime
87

9-
try:
10-
importpsutil
11-
exceptImportError:
12-
psutil=None
13-
148
fromshutilimportrmtree
15-
fromsiximportraise_from
9+
fromsiximportraise_from,iteritems
1610
fromtempfileimportmkstemp,mkdtemp
1711

1812
from .enumsimportNodeStatus,ProcessType
@@ -70,6 +64,28 @@
7064
from .backupimportNodeBackup
7165

7266

67+
classProcessProxy(object):
68+
"""
69+
Wrapper for psutil.Process
70+
71+
Attributes:
72+
process: wrapped psutill.Process object
73+
ptype: instance of ProcessType
74+
"""
75+
76+
def__init__(self,process):
77+
self.process=process
78+
self.ptype=ProcessType.from_process(process)
79+
80+
def__getattr__(self,name):
81+
returngetattr(self.process,name)
82+
83+
def__str__(self):
84+
pid=self.process.pid
85+
cmdline=' '.join(self.process.cmdline()).strip()
86+
return'{} [{}]'.format(cmdline,pid)
87+
88+
7389
classPostgresNode(object):
7490
def__init__(self,name=None,port=None,base_dir=None):
7591
"""
@@ -122,11 +138,88 @@ def __exit__(self, type, value, traceback):
122138

123139
@property
124140
defpid(self):
125-
returnself.get_main_pid()
141+
"""
142+
Return postmaster's PID if node is running, else 0.
143+
"""
144+
145+
ifself.status():
146+
pid_file=os.path.join(self.data_dir,PG_PID_FILE)
147+
withio.open(pid_file)asf:
148+
returnint(f.readline())
149+
150+
# for clarity
151+
return0
126152

127153
@property
128154
defauxiliary_pids(self):
129-
returnself.get_auxiliary_pids()
155+
"""
156+
Returns a dict of { ProcessType : PID }.
157+
"""
158+
159+
result= {}
160+
161+
forprocessinself.auxiliary_processes:
162+
ifprocess.ptypenotinresult:
163+
result[process.ptype]= []
164+
165+
result[process.ptype].append(process.pid)
166+
167+
returnresult
168+
169+
@property
170+
defauxiliary_processes(self):
171+
"""
172+
Returns a list of auxiliary processes.
173+
Each process is represented by ProcessProxy object.
174+
"""
175+
176+
defis_aux(process):
177+
returnprocess.ptype!=ProcessType.Unknown
178+
179+
returnlist(filter(is_aux,self.child_processes))
180+
181+
@property
182+
defchild_processes(self):
183+
"""
184+
Returns a list of all child processes.
185+
Each process is represented by ProcessProxy object.
186+
"""
187+
188+
try:
189+
importpsutil
190+
exceptImportError:
191+
raiseTestgresException("psutil module is not installed")
192+
193+
# get a list of postmaster's children
194+
children=psutil.Process(self.pid).children()
195+
196+
return [ProcessProxy(p)forpinchildren]
197+
198+
@property
199+
defsource_walsender(self):
200+
"""
201+
Returns master's walsender feeding this replica.
202+
"""
203+
204+
sql="""
205+
select pid
206+
from pg_catalog.pg_stat_replication
207+
where application_name = $1
208+
"""
209+
210+
ifnotself.master:
211+
raiseTestgresException("Node doesn't have a master")
212+
213+
# master should be on the same host
214+
assertself.master.host==self.host
215+
216+
withself.master.connect()ascon:
217+
forrowincon.execute(sql,self.name):
218+
forchildinself.master.auxiliary_processes:
219+
ifchild.pid==int(row[0]):
220+
returnchild
221+
222+
raiseQueryException("Master doesn't send WAL to {}",self.name)
130223

131224
@property
132225
defmaster(self):
@@ -427,98 +520,6 @@ def status(self):
427520
elife.exit_code==4:
428521
returnNodeStatus.Uninitialized
429522

430-
defget_main_pid(self):
431-
"""
432-
Return postmaster's PID if node is running, else 0.
433-
"""
434-
435-
ifself.status():
436-
pid_file=os.path.join(self.data_dir,PG_PID_FILE)
437-
withio.open(pid_file)asf:
438-
returnint(f.readline())
439-
440-
# for clarity
441-
return0
442-
443-
defget_child_processes(self):
444-
''' Returns child processes for this node '''
445-
446-
ifpsutilisNone:
447-
raiseTestgresException("psutil module is not installed")
448-
449-
try:
450-
postmaster=psutil.Process(self.pid)
451-
exceptpsutil.NoSuchProcess:
452-
returnNone
453-
454-
returnpostmaster.children(recursive=True)
455-
456-
defget_auxiliary_pids(self):
457-
''' Returns dict with pids of auxiliary processes '''
458-
459-
alternative_names= {
460-
ProcessType.LogicalReplicationLauncher: [
461-
'postgres: bgworker: logical replication launcher'
462-
],
463-
ProcessType.BackgroundWriter: [
464-
'postgres: writer',
465-
],
466-
ProcessType.WalWriter: [
467-
'postgres: wal writer',
468-
],
469-
ProcessType.WalReceiver: [
470-
'postgres: wal receiver',
471-
],
472-
}
473-
474-
children=self.get_child_processes()
475-
ifchildrenisNone:
476-
returnNone
477-
478-
result= {}
479-
forchildinchildren:
480-
line=' '.join(child.cmdline())
481-
forptypeinProcessType:
482-
ifptype==ProcessType.WalSender \
483-
and (line.startswith(ptype.value)or
484-
line.startswith('postgres: wal sender')):
485-
result.setdefault(ptype, [])
486-
result[ptype].append(child.pid)
487-
break
488-
elifline.startswith(ptype.value):
489-
result[ptype]=child.pid
490-
break
491-
elifptypeinalternative_names:
492-
names=alternative_names[ptype]
493-
fornameinnames:
494-
ifline.startswith(name):
495-
result[ptype]=child.pid
496-
break
497-
498-
returnresult
499-
500-
defget_walsender_pid(self):
501-
''' Returns pid of according walsender for replica '''
502-
503-
ifnotself._master:
504-
raiseTestgresException("This node is not a replica")
505-
506-
children=self._master.get_child_processes()
507-
ifchildrenisNone:
508-
returnNone
509-
510-
sql='select application_name, client_port from pg_stat_replication'
511-
forname,client_portinself._master.execute(sql):
512-
ifname==self.name:
513-
forchildinchildren:
514-
line=' '.join(child.cmdline())
515-
if (line.startswith(ProcessType.WalSender.value)or
516-
line.startswith('postgres: wal sender'))and \
517-
str(client_port)inline:
518-
returnchild.pid
519-
520-
returnNone
521-
522523
defget_control_data(self):
523524
"""
524525
Return contents of pg_control file.
@@ -1079,7 +1080,7 @@ def pgbench_run(self,
10791080
"-U",username,
10801081
]+options
10811082

1082-
forkey,valueinsix.iteritems(kwargs):
1083+
forkey,valueiniteritems(kwargs):
10831084
# rename keys for pgbench
10841085
key=key.replace('_','-')
10851086

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp