PostgreSQL Source Code: src/backend/utils/misc/injection_point.c Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

19

21

22#ifdef USE_INJECTION_POINTS

23

24#include <sys/stat.h>

25

33

34

35#define INJ_NAME_MAXLEN 64

36#define INJ_LIB_MAXLEN 128

37#define INJ_FUNC_MAXLEN 128

38#define INJ_PRIVATE_MAXLEN 1024

39

40

41typedef struct InjectionPointEntry

42{

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

62

64 char library[INJ_LIB_MAXLEN];

65 char function[INJ_FUNC_MAXLEN];

66

67

68

69

70

71 char private_data[INJ_PRIVATE_MAXLEN];

72} InjectionPointEntry;

73

74#define MAX_INJECTION_POINTS 128

75

76

77

78

79

80

81

82

83typedef struct InjectionPointsCtl

84{

86 InjectionPointEntry entries[MAX_INJECTION_POINTS];

87} InjectionPointsCtl;

88

90

91

92

93

94

95typedef struct InjectionPointCacheEntry

96{

98 char private_data[INJ_PRIVATE_MAXLEN];

100

101

102

103

104

105

106 int slot_idx;

108} InjectionPointCacheEntry;

109

110static HTAB *InjectionPointCache = NULL;

111

112

113

114

115

116

117static InjectionPointCacheEntry *

118injection_point_cache_add(const char *name,

119 int slot_idx,

122 const void *private_data)

123{

124 InjectionPointCacheEntry *entry;

125 bool found;

126

127

128 if (InjectionPointCache == NULL)

129 {

131

133 hash_ctl.entrysize = sizeof(InjectionPointCacheEntry);

135

136 InjectionPointCache = hash_create("InjectionPoint cache hash",

137 MAX_INJECTION_POINTS,

138 &hash_ctl,

140 }

141

142 entry = (InjectionPointCacheEntry *)

144

146 strlcpy(entry->name, name, sizeof(entry->name));

147 entry->slot_idx = slot_idx;

148 entry->generation = generation;

150 memcpy(entry->private_data, private_data, INJ_PRIVATE_MAXLEN);

151

152 return entry;

153}

154

155

156

157

158

159

160

161

162static void

163injection_point_cache_remove(const char *name)

164{

166

169}

170

171

172

173

174

175

176static InjectionPointCacheEntry *

177injection_point_cache_load(InjectionPointEntry *entry, int slot_idx, uint64 generation)

178{

180 void *injection_callback_local;

181

183 entry->library, DLSUFFIX);

184

186 elog(ERROR, "could not find library \"%s\" for injection point \"%s\"",

187 path, entry->name);

188

189 injection_callback_local = (void *)

191

192 if (injection_callback_local == NULL)

193 elog(ERROR, "could not find function \"%s\" in library \"%s\" for injection point \"%s\"",

194 entry->function, path, entry->name);

195

196

197 return injection_point_cache_add(entry->name,

198 slot_idx,

199 generation,

200 injection_callback_local,

201 entry->private_data);

202}

203

204

205

206

207

208

209static InjectionPointCacheEntry *

210injection_point_cache_get(const char *name)

211{

212 bool found;

213 InjectionPointCacheEntry *entry;

214

215

216 if (InjectionPointCache == NULL)

217 return NULL;

218

219 entry = (InjectionPointCacheEntry *)

221

222 if (found)

223 return entry;

224

225 return NULL;

226}

227#endif

228

229

230

231

234{

235#ifdef USE_INJECTION_POINTS

237

238 sz = add_size(sz, sizeof(InjectionPointsCtl));

239 return sz;

240#else

241 return 0;

242#endif

243}

244

245

246

247

248void

250{

251#ifdef USE_INJECTION_POINTS

252 bool found;

253

254 ActiveInjectionPoints = ShmemInitStruct("InjectionPoint hash",

255 sizeof(InjectionPointsCtl),

256 &found);

258 {

261 for (int i = 0; i < MAX_INJECTION_POINTS; i++)

263 }

264 else

266#endif

267}

268

269

270

271

272void

274 const char *library,

276 const void *private_data,

277 int private_data_size)

278{

279#ifdef USE_INJECTION_POINTS

280 InjectionPointEntry *entry;

283 int free_idx;

284

286 elog(ERROR, "injection point name %s too long (maximum of %u)",

288 if (strlen(library) >= INJ_LIB_MAXLEN)

289 elog(ERROR, "injection point library %s too long (maximum of %u)",

290 library, INJ_LIB_MAXLEN);

291 if (strlen(function) >= INJ_FUNC_MAXLEN)

292 elog(ERROR, "injection point function %s too long (maximum of %u)",

294 if (private_data_size >= INJ_PRIVATE_MAXLEN)

295 elog(ERROR, "injection point data too long (maximum of %u)",

296 INJ_PRIVATE_MAXLEN);

297

298

299

300

301

304 free_idx = -1;

305

306 for (int idx = 0; idx < max_inuse; idx++)

307 {

308 entry = &ActiveInjectionPoints->entries[idx];

310 if (generation % 2 == 0)

311 {

312

313

314

315

316 if (free_idx == -1)

317 free_idx = idx;

318 }

319 else if (strcmp(entry->name, name) == 0)

320 elog(ERROR, "injection point \"%s\" already defined", name);

321 }

322 if (free_idx == -1)

323 {

324 if (max_inuse == MAX_INJECTION_POINTS)

325 elog(ERROR, "too many injection points");

326 free_idx = max_inuse;

327 }

328 entry = &ActiveInjectionPoints->entries[free_idx];

330 Assert(generation % 2 == 0);

331

332

333 strlcpy(entry->name, name, sizeof(entry->name));

335 strlcpy(entry->library, library, sizeof(entry->library));

336 entry->library[INJ_LIB_MAXLEN - 1] = '\0';

337 strlcpy(entry->function, function, sizeof(entry->function));

338 entry->function[INJ_FUNC_MAXLEN - 1] = '\0';

339 if (private_data != NULL)

340 memcpy(entry->private_data, private_data, private_data_size);

341

344

345 if (free_idx + 1 > max_inuse)

347

349

350#else

351 elog(ERROR, "injection points are not supported by this build");

352#endif

353}

354

355

356

357

358

359

360bool

362{

363#ifdef USE_INJECTION_POINTS

364 bool found = false;

366 int max_inuse;

367

369

370

371 max_inuse = (int) pg_atomic_read_u32(&ActiveInjectionPoints->max_inuse);

372 for (idx = max_inuse - 1; idx >= 0; --idx)

373 {

374 InjectionPointEntry *entry = &ActiveInjectionPoints->entries[idx];

376

378 if (generation % 2 == 0)

379 continue;

380

381 if (strcmp(entry->name, name) == 0)

382 {

384 found = true;

386 break;

387 }

388 }

389

390

391 if (found && idx == max_inuse - 1)

392 {

393 for (; idx >= 0; --idx)

394 {

395 InjectionPointEntry *entry = &ActiveInjectionPoints->entries[idx];

397

399 if (generation % 2 != 0)

400 break;

401 }

403 }

405

406 return found;

407#else

408 elog(ERROR, "Injection points are not supported by this build");

409 return true;

410#endif

411}

412

413#ifdef USE_INJECTION_POINTS

414

415

416

417

418

419

420static InjectionPointCacheEntry *

421InjectionPointCacheRefresh(const char *name)

422{

424 int namelen;

425 InjectionPointEntry local_copy;

426 InjectionPointCacheEntry *cached;

427

428

429

430

431

432

433

435 if (max_inuse == 0)

436 {

437 if (InjectionPointCache)

438 {

440 InjectionPointCache = NULL;

441 }

442 return NULL;

443 }

444

445

446

447

448

449 cached = injection_point_cache_get(name);

450 if (cached)

451 {

452 int idx = cached->slot_idx;

453 InjectionPointEntry *entry = &ActiveInjectionPoints->entries[idx];

454

456 {

457

458 return cached;

459 }

460 injection_point_cache_remove(name);

461 cached = NULL;

462 }

463

464

465

466

467

468

469

470

471

472

473 namelen = strlen(name);

474 for (int idx = 0; idx < max_inuse; idx++)

475 {

476 InjectionPointEntry *entry = &ActiveInjectionPoints->entries[idx];

478

479

480

481

482

483

485 if (generation % 2 == 0)

486 continue;

488

489

490 if (memcmp(entry->name, name, namelen + 1) != 0)

491 continue;

492

493

494

495

496

497

498

499 memcpy(&local_copy, entry, sizeof(InjectionPointEntry));

500

503 {

504

505

506

507

508

509

510

511

512

513 continue;

514 }

515

516

517 return injection_point_cache_load(&local_copy, idx, generation);

518 }

519 return NULL;

520}

521#endif

522

523

524

525

526

527

528

529

530void

532{

533#ifdef USE_INJECTION_POINTS

534 InjectionPointCacheRefresh(name);

535#else

536 elog(ERROR, "Injection points are not supported by this build");

537#endif

538}

539

540

541

542

543void

545{

546#ifdef USE_INJECTION_POINTS

547 InjectionPointCacheEntry *cache_entry;

548

549 cache_entry = InjectionPointCacheRefresh(name);

550 if (cache_entry)

551 cache_entry->callback(name, cache_entry->private_data, arg);

552#else

553 elog(ERROR, "Injection points are not supported by this build");

554#endif

555}

556

557

558

559

560void

562{

563#ifdef USE_INJECTION_POINTS

564 InjectionPointCacheEntry *cache_entry;

565

566 cache_entry = injection_point_cache_get(name);

567 if (cache_entry)

568 cache_entry->callback(name, cache_entry->private_data, arg);

569#else

570 elog(ERROR, "Injection points are not supported by this build");

571#endif

572}

573

574

575

576

577bool

579{

580#ifdef USE_INJECTION_POINTS

581 return InjectionPointCacheRefresh(name) != NULL;

582#else

583 elog(ERROR, "Injection points are not supported by this build");

584 return false;

585#endif

586}

Datum idx(PG_FUNCTION_ARGS)

static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)

#define pg_read_barrier()

static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)

#define pg_write_barrier()

static void pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)

static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)

static void pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)

static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)

#define PG_USED_FOR_ASSERTS_ONLY

void * load_external_function(const char *filename, const char *funcname, bool signalNotFound, void **filehandle)

void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)

void hash_destroy(HTAB *hashp)

HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)

bool pg_file_exists(const char *name)

char pkglib_path[MAXPGPATH]

Assert(PointerIsAligned(start, uint64))

void InjectionPointShmemInit(void)

Size InjectionPointShmemSize(void)

void InjectionPointLoad(const char *name)

bool InjectionPointDetach(const char *name)

void InjectionPointRun(const char *name, void *arg)

bool IsInjectionPointAttached(const char *name)

void InjectionPointAttach(const char *name, const char *library, const char *function, const void *private_data, int private_data_size)

void InjectionPointCached(const char *name, void *arg)

void(* InjectionPointCallback)(const char *name, const void *private_data, void *arg)

bool LWLockAcquire(LWLock *lock, LWLockMode mode)

void LWLockRelease(LWLock *lock)

MemoryContext TopMemoryContext

on_exit_nicely_callback function

size_t strlcpy(char *dst, const char *src, size_t siz)

Size add_size(Size s1, Size s2)

void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)

static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)