tep 0.11.4 → 0.11.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Makefile +11 -1
- data/bin/tep +39 -2
- data/examples/pg_hello.rb +11 -1
- data/lib/tep/broadcast.rb +18 -80
- data/lib/tep/net.rb +8 -3
- data/lib/tep/pg.rb +468 -14
- data/lib/tep/presence.rb +22 -318
- data/lib/tep/version.rb +1 -1
- data/lib/tep.rb +26 -107
- data/spinel-ext.json +6 -0
- data/test/test_broadcast_pg.rb +1 -0
- data/test/test_pg.rb +1 -0
- data/test/test_presence_pg.rb +1 -0
- metadata +15 -1
data/lib/tep/pg.rb
CHANGED
|
@@ -197,20 +197,34 @@ module PG
|
|
|
197
197
|
h = Pg.tep_pg_connect(opts)
|
|
198
198
|
end
|
|
199
199
|
else
|
|
200
|
-
#
|
|
201
|
-
#
|
|
202
|
-
#
|
|
203
|
-
#
|
|
204
|
-
#
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
200
|
+
# ============ WORKAROUND -- REMOVE WHEN UPSTREAM LANDS ============
|
|
201
|
+
# Hash-conninfo form. The `opts.each` below miscompiles at spinel
|
|
202
|
+
# master: `opts` is a String|Hash param, but in this is_a?(String)
|
|
203
|
+
# ELSE branch spinel types it String (the is_a?-else narrowing
|
|
204
|
+
# gap, matz/spinel#1434) and rejects `opts.each` as String#each
|
|
205
|
+
# -- the lone blocker to re-pinning tep onto master (tep#196).
|
|
206
|
+
#
|
|
207
|
+
# The Hash form is currently UNUSED + untested in tep and toy:
|
|
208
|
+
# every PG::Connection.new / PG.connect caller passes a String
|
|
209
|
+
# conninfo (AR connects with the String form too). So we stub
|
|
210
|
+
# this dead branch to a failed connection to unblock the re-pin.
|
|
211
|
+
#
|
|
212
|
+
# RESTORE the original kv-pack loop (preserved below) once the
|
|
213
|
+
# upstream narrowing fix lands, and re-add Hash-form test
|
|
214
|
+
# coverage. Until then a Hash arg yields a failed Connection
|
|
215
|
+
# (connected? == false) rather than a miscompile.
|
|
216
|
+
#
|
|
217
|
+
# keys = ""
|
|
218
|
+
# vals = ""
|
|
219
|
+
# n = 0
|
|
220
|
+
# opts.each do |k, v|
|
|
221
|
+
# keys = keys + k + "\0"
|
|
222
|
+
# vals = vals + v + "\0"
|
|
223
|
+
# n += 1
|
|
224
|
+
# end
|
|
225
|
+
# h = Pg.tep_pg_connect_kv(keys, vals, n)
|
|
226
|
+
h = -1
|
|
227
|
+
# =================================================================
|
|
214
228
|
end
|
|
215
229
|
if h < 0
|
|
216
230
|
# Slot 0 holds the most recent connect-failure error message
|
|
@@ -1126,3 +1140,443 @@ module PG
|
|
|
1126
1140
|
end
|
|
1127
1141
|
end
|
|
1128
1142
|
end
|
|
1143
|
+
|
|
1144
|
+
# ===================================================================
|
|
1145
|
+
# Opt-in PG backend overrides (#216). Loaded only via `require "tep/pg"`.
|
|
1146
|
+
# These REDEFINE the no-op hooks in core Broadcast/Presence (last-
|
|
1147
|
+
# definition-wins) so a PG app gets the real LISTEN/NOTIFY + mirror
|
|
1148
|
+
# behavior, while a non-PG app keeps the no-ops and DCEs libpq.
|
|
1149
|
+
# ===================================================================
|
|
1150
|
+
module Tep
|
|
1151
|
+
module Broadcast
|
|
1152
|
+
# Cross-worker NOTIFY override (#216). Replaces the core no-op so a
|
|
1153
|
+
# `require "tep/pg"` app fans publishes out to other workers over the
|
|
1154
|
+
# LISTEN/NOTIFY channel. Mirrors the pre-#216 inline branch in
|
|
1155
|
+
# Broadcast.publish.
|
|
1156
|
+
def self.cross_worker_notify(topic, payload)
|
|
1157
|
+
if Tep::APP.broadcast_pg_enabled != 0
|
|
1158
|
+
wire = Tep::Broadcast.encode_wire(topic, payload)
|
|
1159
|
+
Tep::APP.broadcast_pg_conn.notify(
|
|
1160
|
+
Tep::APP.broadcast_pg_channel, wire)
|
|
1161
|
+
end
|
|
1162
|
+
0
|
|
1163
|
+
end
|
|
1164
|
+
|
|
1165
|
+
def self.enable_pg_backend(conninfo, channel)
|
|
1166
|
+
conn = PG::Connection.new(conninfo)
|
|
1167
|
+
if conn.pgh < 0
|
|
1168
|
+
return -1
|
|
1169
|
+
end
|
|
1170
|
+
if conn.listen(channel) < 0
|
|
1171
|
+
return -1
|
|
1172
|
+
end
|
|
1173
|
+
Tep::APP.set_broadcast_pg_conn(conn)
|
|
1174
|
+
Tep::APP.set_broadcast_pg_channel(channel)
|
|
1175
|
+
Tep::APP.set_broadcast_pg_enabled(1)
|
|
1176
|
+
0
|
|
1177
|
+
end
|
|
1178
|
+
|
|
1179
|
+
def self.disable_pg_backend
|
|
1180
|
+
if Tep::APP.broadcast_pg_enabled == 0
|
|
1181
|
+
return 0
|
|
1182
|
+
end
|
|
1183
|
+
Tep::APP.broadcast_pg_conn.unlisten(Tep::APP.broadcast_pg_channel)
|
|
1184
|
+
Tep::APP.broadcast_pg_conn.finish
|
|
1185
|
+
Tep::APP.set_broadcast_pg_enabled(0)
|
|
1186
|
+
0
|
|
1187
|
+
end
|
|
1188
|
+
|
|
1189
|
+
def self.poll_pg_once(timeout_ms)
|
|
1190
|
+
if Tep::APP.broadcast_pg_enabled == 0
|
|
1191
|
+
return -1
|
|
1192
|
+
end
|
|
1193
|
+
r = Tep::APP.broadcast_pg_conn.poll_notification(timeout_ms)
|
|
1194
|
+
if r != 1
|
|
1195
|
+
return r
|
|
1196
|
+
end
|
|
1197
|
+
wire = Tep::APP.broadcast_pg_conn.last_notify_payload
|
|
1198
|
+
Tep::Broadcast.deliver_wire_local(wire)
|
|
1199
|
+
1
|
|
1200
|
+
end
|
|
1201
|
+
|
|
1202
|
+
def self.encode_wire(topic, payload)
|
|
1203
|
+
topic.length.to_s + ":" + topic + payload
|
|
1204
|
+
end
|
|
1205
|
+
|
|
1206
|
+
def self.deliver_wire_local(wire)
|
|
1207
|
+
colon = Tep.str_find(wire, ":", 0)
|
|
1208
|
+
if colon <= 0
|
|
1209
|
+
return -1
|
|
1210
|
+
end
|
|
1211
|
+
len_str = wire[0, colon]
|
|
1212
|
+
tlen = len_str.to_i
|
|
1213
|
+
if tlen < 0 || colon + 1 + tlen > wire.length
|
|
1214
|
+
return -1
|
|
1215
|
+
end
|
|
1216
|
+
topic = wire[colon + 1, tlen]
|
|
1217
|
+
payload = wire[colon + 1 + tlen, wire.length - colon - 1 - tlen]
|
|
1218
|
+
Tep::Broadcast.publish_local_only(topic, payload)
|
|
1219
|
+
end
|
|
1220
|
+
|
|
1221
|
+
end
|
|
1222
|
+
|
|
1223
|
+
module Presence
|
|
1224
|
+
def self.enable_pg_mirror(conninfo)
|
|
1225
|
+
conn = PG::Connection.new(conninfo)
|
|
1226
|
+
if conn.pgh < 0
|
|
1227
|
+
return -1
|
|
1228
|
+
end
|
|
1229
|
+
# exec raises PG::Error on failure now; degrade gracefully
|
|
1230
|
+
# (close + return -1) rather than letting it escape the worker.
|
|
1231
|
+
begin
|
|
1232
|
+
r = conn.exec(Tep::Presence.schema_sql)
|
|
1233
|
+
r.clear
|
|
1234
|
+
# Heartbeat table for the prune-stale-workers path (#47).
|
|
1235
|
+
r = conn.exec(Tep::Presence.worker_schema_sql)
|
|
1236
|
+
r.clear
|
|
1237
|
+
rescue PG::Error
|
|
1238
|
+
conn.finish
|
|
1239
|
+
return -1
|
|
1240
|
+
end
|
|
1241
|
+
Tep::APP.set_presence_pg_conn(conn)
|
|
1242
|
+
worker_id = Sock.sphttp_getpid.to_s + "-" + Time.now.to_i.to_s
|
|
1243
|
+
Tep::APP.set_presence_pg_worker_id(worker_id)
|
|
1244
|
+
Tep::APP.set_presence_pg_enabled(1)
|
|
1245
|
+
# Drop any rows from a prior worker that managed to leave
|
|
1246
|
+
# stale entries with this same worker_id (unlikely thanks
|
|
1247
|
+
# to the boot-epoch suffix, but defensive). Best-effort.
|
|
1248
|
+
Tep::Presence.mirror_exec(
|
|
1249
|
+
"DELETE FROM tep_presence WHERE worker_id = $1",
|
|
1250
|
+
[worker_id])
|
|
1251
|
+
# Register this worker's heartbeat row immediately. Apps
|
|
1252
|
+
# refresh it periodically via Tep::Presence.heartbeat;
|
|
1253
|
+
# prune_stale_workers deletes rows whose heartbeat is stale.
|
|
1254
|
+
Tep::Presence.heartbeat
|
|
1255
|
+
0
|
|
1256
|
+
end
|
|
1257
|
+
|
|
1258
|
+
def self.disable_pg_mirror
|
|
1259
|
+
if Tep::APP.presence_pg_enabled == 0
|
|
1260
|
+
return 0
|
|
1261
|
+
end
|
|
1262
|
+
# Best-effort cleanup -- swallow PG errors (we're tearing the
|
|
1263
|
+
# mirror down regardless) and still finish + disable below.
|
|
1264
|
+
begin
|
|
1265
|
+
r = Tep::APP.presence_pg_conn.exec_params(
|
|
1266
|
+
"DELETE FROM tep_presence WHERE worker_id = $1",
|
|
1267
|
+
[Tep::APP.presence_pg_worker_id])
|
|
1268
|
+
r.clear
|
|
1269
|
+
# Remove the heartbeat row so prune_stale_workers doesn't
|
|
1270
|
+
# see this worker as live after we're gone.
|
|
1271
|
+
r = Tep::APP.presence_pg_conn.exec_params(
|
|
1272
|
+
"DELETE FROM tep_presence_worker WHERE worker_id = $1",
|
|
1273
|
+
[Tep::APP.presence_pg_worker_id])
|
|
1274
|
+
r.clear
|
|
1275
|
+
rescue PG::Error
|
|
1276
|
+
# swallow -- shutting the mirror down anyway
|
|
1277
|
+
end
|
|
1278
|
+
Tep::APP.presence_pg_conn.finish
|
|
1279
|
+
Tep::APP.set_presence_pg_enabled(0)
|
|
1280
|
+
0
|
|
1281
|
+
end
|
|
1282
|
+
|
|
1283
|
+
def self.schema_sql
|
|
1284
|
+
"CREATE TABLE IF NOT EXISTS tep_presence (" +
|
|
1285
|
+
"worker_id TEXT NOT NULL, " +
|
|
1286
|
+
"topic TEXT NOT NULL, " +
|
|
1287
|
+
"fd INTEGER NOT NULL, " +
|
|
1288
|
+
"principal_id TEXT NOT NULL, " +
|
|
1289
|
+
"kind TEXT NOT NULL, " +
|
|
1290
|
+
"agent_id TEXT NOT NULL, " +
|
|
1291
|
+
"since_ts BIGINT NOT NULL, " +
|
|
1292
|
+
"status_state TEXT NOT NULL, " +
|
|
1293
|
+
"status_note TEXT NOT NULL, " +
|
|
1294
|
+
"status_until BIGINT NOT NULL, " +
|
|
1295
|
+
"PRIMARY KEY (worker_id, topic, fd)" +
|
|
1296
|
+
")"
|
|
1297
|
+
end
|
|
1298
|
+
|
|
1299
|
+
def self.worker_schema_sql
|
|
1300
|
+
"CREATE TABLE IF NOT EXISTS tep_presence_worker (" +
|
|
1301
|
+
"worker_id TEXT PRIMARY KEY, " +
|
|
1302
|
+
"last_seen_ts BIGINT NOT NULL" +
|
|
1303
|
+
")"
|
|
1304
|
+
end
|
|
1305
|
+
|
|
1306
|
+
def self.heartbeat
|
|
1307
|
+
if Tep::APP.presence_pg_enabled == 0
|
|
1308
|
+
return 0
|
|
1309
|
+
end
|
|
1310
|
+
wid = Tep::APP.presence_pg_worker_id
|
|
1311
|
+
if wid.length == 0
|
|
1312
|
+
return 0
|
|
1313
|
+
end
|
|
1314
|
+
begin
|
|
1315
|
+
r = Tep::APP.presence_pg_conn.exec_params(
|
|
1316
|
+
"INSERT INTO tep_presence_worker (worker_id, last_seen_ts) " +
|
|
1317
|
+
"VALUES ($1, $2) " +
|
|
1318
|
+
"ON CONFLICT (worker_id) DO UPDATE SET " +
|
|
1319
|
+
" last_seen_ts = EXCLUDED.last_seen_ts",
|
|
1320
|
+
[wid, Time.now.to_i.to_s])
|
|
1321
|
+
r.clear
|
|
1322
|
+
rescue PG::Error
|
|
1323
|
+
return 0
|
|
1324
|
+
end
|
|
1325
|
+
1
|
|
1326
|
+
end
|
|
1327
|
+
|
|
1328
|
+
def self.prune_stale_workers(ttl_seconds)
|
|
1329
|
+
if Tep::APP.presence_pg_enabled == 0
|
|
1330
|
+
return 0
|
|
1331
|
+
end
|
|
1332
|
+
cutoff = Time.now.to_i - ttl_seconds
|
|
1333
|
+
conn = Tep::APP.presence_pg_conn
|
|
1334
|
+
begin
|
|
1335
|
+
# Drop dead heartbeats first; the second DELETE then walks
|
|
1336
|
+
# the worker_id space that's still alive.
|
|
1337
|
+
r1 = conn.exec_params(
|
|
1338
|
+
"DELETE FROM tep_presence_worker WHERE last_seen_ts < $1",
|
|
1339
|
+
[cutoff.to_s])
|
|
1340
|
+
r1.clear
|
|
1341
|
+
# Now drop presence rows whose worker_id isn't in the live
|
|
1342
|
+
# heartbeat table. NOT IN handles both crashed-and-pruned
|
|
1343
|
+
# workers and workers that never registered (legacy rows
|
|
1344
|
+
# from before this prune feature shipped).
|
|
1345
|
+
r2 = conn.exec(
|
|
1346
|
+
"DELETE FROM tep_presence " +
|
|
1347
|
+
"WHERE worker_id NOT IN (SELECT worker_id FROM tep_presence_worker)")
|
|
1348
|
+
n = r2.cmd_tuples
|
|
1349
|
+
r2.clear
|
|
1350
|
+
rescue PG::Error
|
|
1351
|
+
return 0
|
|
1352
|
+
end
|
|
1353
|
+
n
|
|
1354
|
+
end
|
|
1355
|
+
|
|
1356
|
+
def self.mirror_exec(sql, params)
|
|
1357
|
+
begin
|
|
1358
|
+
r = Tep::APP.presence_pg_conn.exec_params(sql, params)
|
|
1359
|
+
r.clear
|
|
1360
|
+
rescue PG::Error
|
|
1361
|
+
# swallow -- advisory mirror, local presence is authoritative
|
|
1362
|
+
end
|
|
1363
|
+
0
|
|
1364
|
+
end
|
|
1365
|
+
|
|
1366
|
+
def self.mirror_insert(entry)
|
|
1367
|
+
if Tep::APP.presence_pg_enabled == 0
|
|
1368
|
+
return 0
|
|
1369
|
+
end
|
|
1370
|
+
Tep::Presence.mirror_exec(
|
|
1371
|
+
"INSERT INTO tep_presence " +
|
|
1372
|
+
"(worker_id, topic, fd, principal_id, kind, agent_id, " +
|
|
1373
|
+
" since_ts, status_state, status_note, status_until) " +
|
|
1374
|
+
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) " +
|
|
1375
|
+
"ON CONFLICT (worker_id, topic, fd) DO UPDATE SET " +
|
|
1376
|
+
" principal_id = EXCLUDED.principal_id, " +
|
|
1377
|
+
" kind = EXCLUDED.kind, " +
|
|
1378
|
+
" agent_id = EXCLUDED.agent_id, " +
|
|
1379
|
+
" since_ts = EXCLUDED.since_ts, " +
|
|
1380
|
+
" status_state = EXCLUDED.status_state, " +
|
|
1381
|
+
" status_note = EXCLUDED.status_note, " +
|
|
1382
|
+
" status_until = EXCLUDED.status_until",
|
|
1383
|
+
[
|
|
1384
|
+
Tep::APP.presence_pg_worker_id,
|
|
1385
|
+
entry.topic,
|
|
1386
|
+
entry.fd.to_s,
|
|
1387
|
+
entry.principal_id,
|
|
1388
|
+
entry.kind.to_s,
|
|
1389
|
+
entry.agent_id,
|
|
1390
|
+
entry.since.to_s,
|
|
1391
|
+
entry.status_state.to_s,
|
|
1392
|
+
entry.status_note,
|
|
1393
|
+
entry.status_until.to_s
|
|
1394
|
+
])
|
|
1395
|
+
end
|
|
1396
|
+
|
|
1397
|
+
def self.mirror_delete(topic, fd)
|
|
1398
|
+
if Tep::APP.presence_pg_enabled == 0
|
|
1399
|
+
return 0
|
|
1400
|
+
end
|
|
1401
|
+
Tep::Presence.mirror_exec(
|
|
1402
|
+
"DELETE FROM tep_presence " +
|
|
1403
|
+
"WHERE worker_id = $1 AND topic = $2 AND fd = $3",
|
|
1404
|
+
[Tep::APP.presence_pg_worker_id, topic, fd.to_s])
|
|
1405
|
+
end
|
|
1406
|
+
|
|
1407
|
+
def self.mirror_status(topic, fd, state, note, until_ts)
|
|
1408
|
+
if Tep::APP.presence_pg_enabled == 0
|
|
1409
|
+
return 0
|
|
1410
|
+
end
|
|
1411
|
+
Tep::Presence.mirror_exec(
|
|
1412
|
+
"UPDATE tep_presence " +
|
|
1413
|
+
"SET status_state = $4, status_note = $5, status_until = $6 " +
|
|
1414
|
+
"WHERE worker_id = $1 AND topic = $2 AND fd = $3",
|
|
1415
|
+
[Tep::APP.presence_pg_worker_id, topic, fd.to_s,
|
|
1416
|
+
state.to_s, note, until_ts.to_s])
|
|
1417
|
+
end
|
|
1418
|
+
|
|
1419
|
+
def self.list_global(topic)
|
|
1420
|
+
result = [Tep::PresenceEntry.new("", "", :human, "", -1, 0)]
|
|
1421
|
+
result.delete_at(0)
|
|
1422
|
+
if Tep::APP.presence_pg_enabled == 0
|
|
1423
|
+
return result
|
|
1424
|
+
end
|
|
1425
|
+
begin
|
|
1426
|
+
r = Tep::APP.presence_pg_conn.exec_params(
|
|
1427
|
+
"SELECT principal_id, kind, agent_id, fd, since_ts, " +
|
|
1428
|
+
" status_state, status_note, status_until " +
|
|
1429
|
+
"FROM tep_presence WHERE topic = $1 ORDER BY since_ts",
|
|
1430
|
+
[topic])
|
|
1431
|
+
rescue PG::Error
|
|
1432
|
+
return result
|
|
1433
|
+
end
|
|
1434
|
+
i = 0
|
|
1435
|
+
n = r.ntuples
|
|
1436
|
+
while i < n
|
|
1437
|
+
kind_sym = :human
|
|
1438
|
+
if r.getvalue(i, 1) == "agent_for"
|
|
1439
|
+
kind_sym = :agent_for
|
|
1440
|
+
end
|
|
1441
|
+
state_sym = :available
|
|
1442
|
+
sstr = r.getvalue(i, 5)
|
|
1443
|
+
if sstr == "busy"
|
|
1444
|
+
state_sym = :busy
|
|
1445
|
+
elsif sstr == "blocked"
|
|
1446
|
+
state_sym = :blocked
|
|
1447
|
+
end
|
|
1448
|
+
e = Tep::PresenceEntry.new(
|
|
1449
|
+
topic,
|
|
1450
|
+
r.getvalue(i, 0),
|
|
1451
|
+
kind_sym,
|
|
1452
|
+
r.getvalue(i, 2),
|
|
1453
|
+
r.getvalue(i, 3).to_i,
|
|
1454
|
+
r.getvalue(i, 4).to_i)
|
|
1455
|
+
e.status_state = state_sym
|
|
1456
|
+
e.status_note = r.getvalue(i, 6)
|
|
1457
|
+
e.status_until = r.getvalue(i, 7).to_i
|
|
1458
|
+
result.push(e)
|
|
1459
|
+
i += 1
|
|
1460
|
+
end
|
|
1461
|
+
r.clear
|
|
1462
|
+
result
|
|
1463
|
+
end
|
|
1464
|
+
|
|
1465
|
+
def self.count_global(topic)
|
|
1466
|
+
if Tep::APP.presence_pg_enabled == 0
|
|
1467
|
+
return 0
|
|
1468
|
+
end
|
|
1469
|
+
begin
|
|
1470
|
+
r = Tep::APP.presence_pg_conn.exec_params(
|
|
1471
|
+
"SELECT count(*) FROM tep_presence WHERE topic = $1",
|
|
1472
|
+
[topic])
|
|
1473
|
+
rescue PG::Error
|
|
1474
|
+
return 0
|
|
1475
|
+
end
|
|
1476
|
+
n = r.getvalue(0, 0).to_i
|
|
1477
|
+
r.clear
|
|
1478
|
+
n
|
|
1479
|
+
end
|
|
1480
|
+
|
|
1481
|
+
end
|
|
1482
|
+
end
|
|
1483
|
+
|
|
1484
|
+
# ===================================================================
|
|
1485
|
+
# Opt-in PG seeds (#216, relocated from lib/tep.rb). Pin parameter /
|
|
1486
|
+
# return C types for every PG-backed cmeth so a `require "tep/pg"`
|
|
1487
|
+
# app compiles cleanly even when it exercises only a subset.
|
|
1488
|
+
# PG::Connection.new("") returns a failed-conn instance (@pgh<0)
|
|
1489
|
+
# rather than raising, so all of this is safe at module load.
|
|
1490
|
+
# ===================================================================
|
|
1491
|
+
|
|
1492
|
+
# Broadcast PG-backend setters + cmeths. set_* via constant because
|
|
1493
|
+
# PG::Connection.new cannot run inside App#initialize (Tep::APP is
|
|
1494
|
+
# mid-construction). enable_pg_backend("","") connect-fails (-1).
|
|
1495
|
+
Tep::APP.set_broadcast_pg_enabled(0)
|
|
1496
|
+
Tep::APP.set_broadcast_pg_channel("")
|
|
1497
|
+
Tep::APP.set_broadcast_pg_conn(PG::Connection.new(""))
|
|
1498
|
+
Tep::Broadcast.enable_pg_backend("", "")
|
|
1499
|
+
Tep::Broadcast.poll_pg_once(0)
|
|
1500
|
+
Tep::Broadcast.disable_pg_backend
|
|
1501
|
+
Tep::Broadcast.encode_wire("", "")
|
|
1502
|
+
Tep::Broadcast.deliver_wire_local("0:")
|
|
1503
|
+
Tep::Broadcast.cross_worker_notify("_seed", "")
|
|
1504
|
+
|
|
1505
|
+
# Presence PG mirror cmeths. mirror_insert needs a PresenceEntry.
|
|
1506
|
+
_tep_pg_seed_entry = Tep::PresenceEntry.new("_seed", "_seed", :human, "", -1, 0)
|
|
1507
|
+
Tep::Presence.enable_pg_mirror("")
|
|
1508
|
+
Tep::Presence.schema_sql
|
|
1509
|
+
Tep::Presence.mirror_insert(_tep_pg_seed_entry)
|
|
1510
|
+
Tep::Presence.mirror_delete("_seed", -1)
|
|
1511
|
+
Tep::Presence.mirror_status("_seed", -1, :available, "", 0)
|
|
1512
|
+
Tep::Presence.list_global("_seed")
|
|
1513
|
+
Tep::Presence.count_global("_seed")
|
|
1514
|
+
Tep::Presence.worker_schema_sql
|
|
1515
|
+
Tep::Presence.heartbeat
|
|
1516
|
+
Tep::Presence.prune_stale_workers(90)
|
|
1517
|
+
Tep::Presence.disable_pg_mirror
|
|
1518
|
+
Tep::APP.set_presence_pg_enabled(0)
|
|
1519
|
+
Tep::APP.set_presence_pg_worker_id("")
|
|
1520
|
+
Tep::APP.set_presence_pg_conn(PG::Connection.new(""))
|
|
1521
|
+
|
|
1522
|
+
# PG::Connection / Result / Pool type-seeding.
|
|
1523
|
+
_tep_seed_pg_conn = PG::Connection.new("")
|
|
1524
|
+
_tep_seed_pg_conn.connected?
|
|
1525
|
+
_tep_seed_pg_conn.status
|
|
1526
|
+
_tep_seed_pg_conn.transaction_status
|
|
1527
|
+
_tep_seed_pg_conn.server_version
|
|
1528
|
+
_tep_seed_pg_conn.error_message
|
|
1529
|
+
_tep_seed_pg_conn.escape_string("")
|
|
1530
|
+
_tep_seed_pg_conn.escape_identifier("")
|
|
1531
|
+
_tep_seed_pg_conn.escape_literal("")
|
|
1532
|
+
_tep_seed_pg_conn.last_sqlstate = ""
|
|
1533
|
+
_tep_seed_pg_conn.last_error_message = ""
|
|
1534
|
+
_tep_seed_pg_conn.last_result_rh = -1
|
|
1535
|
+
# Async surface seed -- calling these on a failed-conn instance
|
|
1536
|
+
# is harmless (the C shim short-circuits on conn slot < 1).
|
|
1537
|
+
_tep_seed_pg_conn.async_exec("")
|
|
1538
|
+
_tep_seed_pg_seed_arr = [""]
|
|
1539
|
+
_tep_seed_pg_seed_arr.delete_at(0)
|
|
1540
|
+
_tep_seed_pg_conn.async_exec_params("", _tep_seed_pg_seed_arr)
|
|
1541
|
+
# Async connect cmeth. Returns -1 for empty conninfo from a
|
|
1542
|
+
# non-scheduled context (the shim's PQconnectStart-then-FAILED
|
|
1543
|
+
# path), which is type-equivalent to the success path.
|
|
1544
|
+
PG::Connection.async_connect("")
|
|
1545
|
+
# LISTEN / NOTIFY surface (Tep::Broadcast PG backend lands here).
|
|
1546
|
+
_tep_seed_pg_conn.listen("_seed")
|
|
1547
|
+
_tep_seed_pg_conn.unlisten("_seed")
|
|
1548
|
+
_tep_seed_pg_conn.notify("_seed", "")
|
|
1549
|
+
_tep_seed_pg_conn.poll_notification(0)
|
|
1550
|
+
_tep_seed_pg_conn.last_notify_channel
|
|
1551
|
+
_tep_seed_pg_conn.last_notify_payload
|
|
1552
|
+
_tep_seed_pg_res = PG::Result.new(-1)
|
|
1553
|
+
_tep_seed_pg_res.ntuples
|
|
1554
|
+
_tep_seed_pg_res.nfields
|
|
1555
|
+
_tep_seed_pg_res.fname(0)
|
|
1556
|
+
_tep_seed_pg_res.fnumber("")
|
|
1557
|
+
_tep_seed_pg_res.ftype(0)
|
|
1558
|
+
_tep_seed_pg_res.fformat(0)
|
|
1559
|
+
_tep_seed_pg_res.fmod(0)
|
|
1560
|
+
_tep_seed_pg_res.getvalue(0, 0)
|
|
1561
|
+
_tep_seed_pg_res.getisnull(0, 0)
|
|
1562
|
+
_tep_seed_pg_res.getlength(0, 0)
|
|
1563
|
+
_tep_seed_pg_res.value(0, 0)
|
|
1564
|
+
_tep_seed_pg_res.error_field(67)
|
|
1565
|
+
_tep_seed_pg_res.cmd_status
|
|
1566
|
+
_tep_seed_pg_res.cmd_tuples
|
|
1567
|
+
_tep_seed_pg_res.error_message
|
|
1568
|
+
_tep_seed_pg_res.sql_state
|
|
1569
|
+
_tep_seed_pg_res.fields
|
|
1570
|
+
_tep_seed_pg_res.values
|
|
1571
|
+
_tep_seed_pg_res.column_values(0)
|
|
1572
|
+
_tep_seed_pg_res.clear
|
|
1573
|
+
_tep_seed_pg_conn.close
|
|
1574
|
+
# Pool seed -- size 0 so we don't try to open real conns at load.
|
|
1575
|
+
_tep_seed_pg_pool = PG::Pool.new("", 0)
|
|
1576
|
+
_tep_seed_pg_pool.healthy?
|
|
1577
|
+
_tep_seed_pg_pool.available
|
|
1578
|
+
_tep_seed_pg_pool.size
|
|
1579
|
+
_tep_seed_pg_pool.set_checkout_timeout_ms(0)
|
|
1580
|
+
_tep_seed_pg_pool.close_all
|
|
1581
|
+
# NB: don't checkout/checkin against the size-0 seed pool; it'd
|
|
1582
|
+
# spin until timeout. The seed has @free.length=0 forever.
|