00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #include "postgres.h"
00056 #include "utils/hsearch.h"
00057 #include "storage/pg_shmem.h"
00058 #include "storage/shmem.h"
00059 #include "storage/lwlock.h"
00060 #include "access/xact.h"
00061 #include "miscadmin.h"
00062 #include "veil_version.h"
00063 #include "veil_shmem.h"
00064 #include "veil_funcs.h"
00065
00066 #if PG_VERSION_GE(8, 2)
00067
00068
00069
00070
00071
00072 static ShmemCtl *shared_meminfo = NULL;
00073
00074
00075
00076
00077
00078
00079 static bool prepared_for_switch = false;
00080
00081
00082
00083
00084
00085
00086 static LWLockId VeilLWLock = AddinShmemInitLock;
00087
00088
00089
00090
00091
00092 static LWLockId InitialLWLock = AddinShmemInitLock;
00093
00094
00095
00096
00097
00098
00099
00100
00101 #define OTHER_CONTEXT(x) (x ? 0: 1)
00102
00103
00104
00105
00106
00107
00108 static bool using_registered_shmem = false;
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 #ifndef VEIL_TRIAL
00124 void
00125 _PG_init()
00126 {
00127 int veil_dbs;
00128
00129
00130 veil_config_init();
00131 veil_dbs = veil_dbs_in_cluster();
00132
00133
00134 RequestAddinShmemSpace(2 * veil_shmem_context_size() * veil_dbs);
00135
00136
00137 RequestAddinLWLocks(veil_dbs);
00138 }
00139 #endif
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 static HTAB *
00151 create_shared_hash(const char *hashname)
00152 {
00153 HASHCTL hashctl;
00154 HTAB *result;
00155 char *db_hashname;
00156 int hash_elems = veil_shared_hash_elems();
00157
00158
00159
00160 db_hashname = (char *) vl_malloc(HASH_KEYLEN);
00161 (void) snprintf(db_hashname, HASH_KEYLEN - 1, "%s_%u",
00162 hashname, MyDatabaseId);
00163 hashctl.keysize = HASH_KEYLEN;
00164 hashctl.entrysize = sizeof(VarEntry);
00165
00166 result = ShmemInitHash(db_hashname, hash_elems,
00167 hash_elems, &hashctl, HASH_ELEM);
00168 pfree(db_hashname);
00169 return result;
00170 }
00171
00172
00173
00174
00175
00176
00177
00178 static HTAB *
00179 get_hash0()
00180 {
00181 static HTAB *hash0 = NULL;
00182
00183 if (!hash0) {
00184 hash0 = create_shared_hash("VEIL_SHARED1");
00185 }
00186 return hash0;
00187 }
00188
00189
00190
00191
00192
00193
00194
00195 static HTAB *
00196 get_hash1()
00197 {
00198 static HTAB *hash1 = NULL;
00199
00200 if (!hash1) {
00201 hash1 = create_shared_hash("VEIL_SHARED2");
00202 }
00203
00204 return hash1;
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 static MemContext *
00219 get_shmem_context(char *name,
00220 size_t size,
00221 bool *p_found)
00222 {
00223 int i;
00224 MemContext *context;
00225 char *uniqname = (char *) vl_malloc(strlen(name) + 16);
00226 int max_dbs = veil_dbs_in_cluster();
00227
00228 for (i = 0; i < max_dbs; i++) {
00229 (void) sprintf(uniqname, "%s_%d", name, i);
00230 context = ShmemInitStruct(uniqname, size, p_found);;
00231 if (!context) {
00232 ereport(ERROR,
00233 (errcode(ERRCODE_INTERNAL_ERROR),
00234 errmsg("veil: cannot allocate shared memory(1)")));
00235 }
00236
00237 if (*p_found) {
00238
00239 if (context->db_id == MyDatabaseId) {
00240
00241
00242 return context;
00243 }
00244 }
00245 else {
00246
00247 context->db_id = MyDatabaseId;
00248 context->next = sizeof(MemContext);
00249 context->limit = size;
00250 context->lwlock = VeilLWLock;
00251 return context;
00252 }
00253 }
00254
00255
00256
00257
00258
00259 for (i = 0; i < max_dbs; i++) {
00260 (void) sprintf(uniqname, "%s_%d", name, i);
00261 context = ShmemInitStruct(uniqname, size, p_found);;
00262
00263 if (!context) {
00264 ereport(ERROR,
00265 (errcode(ERRCODE_INTERNAL_ERROR),
00266 errmsg("veil: cannot allocate shared memory(2)")));
00267 }
00268
00269 if (*p_found) {
00270
00271 if (!vl_db_exists(context->db_id)) {
00272
00273 context->db_id = MyDatabaseId;
00274 context->next = sizeof(MemContext);
00275 context->limit = size;
00276
00277 *p_found = false;
00278 return context;
00279 }
00280 }
00281 else {
00282
00283
00284
00285 context->db_id = MyDatabaseId;
00286 context->next = sizeof(MemContext);
00287 context->limit = size;
00288 return context;
00289 }
00290 }
00291 ereport(ERROR,
00292 (errcode(ERRCODE_INTERNAL_ERROR),
00293 errmsg("veil: no more shared memory contexts allowed")));
00294 }
00295
00296
00297 static void shmalloc_init();
00298
00299
00300
00301
00302
00303
00304 static int
00305 get_cur_context_id()
00306 {
00307 static initialised = false;
00308 int context;
00309
00310 if (!initialised) {
00311 shmalloc_init();
00312 initialised = true;
00313 }
00314
00315 context = shared_meminfo->current_context;
00316 if (prepared_for_switch) {
00317 context = OTHER_CONTEXT(context);
00318 }
00319 else {
00320
00321
00322 if (TransactionIdPrecedes(GetCurrentTransactionId(),
00323 shared_meminfo->xid[context]))
00324 {
00325 context = OTHER_CONTEXT(context);
00326 }
00327 }
00328
00329 return context;
00330 }
00331
00332
00333
00334
00335
00336
00337 static MemContext *
00338 get_cur_context()
00339 {
00340 int context;
00341 context = get_cur_context_id();
00342 return shared_meminfo->context[context];
00343 }
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354 void *
00355 do_vl_shmalloc(MemContext *context,
00356 size_t size)
00357 {
00358 void *result;
00359 size_t amount = (size_t) MAXALIGN(size);
00360
00361 if ((amount + context->next) <= context->limit) {
00362 result = (void *) context + context->next;
00363 context->next += amount;
00364 }
00365 else {
00366 ereport(ERROR,
00367 (ERROR,
00368 (errcode(ERRCODE_INTERNAL_ERROR),
00369 errmsg("veil: out of shared memory"))));
00370 }
00371 return result;
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381 void *
00382 vl_shmalloc(size_t size)
00383 {
00384 MemContext *context;
00385 void *result;
00386
00387 context = get_cur_context();
00388
00389 LWLockAcquire(VeilLWLock, LW_EXCLUSIVE);
00390 result = do_vl_shmalloc(context, size);
00391 LWLockRelease(VeilLWLock);
00392
00393 return result;
00394 }
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 void
00405 vl_free(void *mem)
00406 {
00407 return;
00408 }
00409
00410
00411
00412
00413
00414
00415 static void
00416 shmalloc_init()
00417 {
00418 if (!shared_meminfo) {
00419 VarEntry *var;
00420 MemContext *context0;
00421 MemContext *context1;
00422 bool found = false;
00423 size_t allocated;
00424 HTAB *hash0;
00425 HTAB *hash1;
00426 size_t size;
00427
00428 size = veil_shmem_context_size();
00429
00430 LWLockAcquire(InitialLWLock, LW_EXCLUSIVE);
00431 context0 = get_shmem_context("VEIL_SHMEM0", size, &found);
00432
00433 if (found) {
00434 shared_meminfo = context0->memctl;
00435 VeilLWLock = shared_meminfo->veil_lwlock;
00436
00437
00438
00439 LWLockAcquire(VeilLWLock, LW_EXCLUSIVE);
00440 LWLockRelease(InitialLWLock);
00441 LWLockRelease(VeilLWLock);
00442 }
00443 else {
00444
00445
00446
00447
00448
00449
00450 shared_meminfo = do_vl_shmalloc(context0, sizeof(ShmemCtl));
00451
00452 if (context0->lwlock != InitialLWLock) {
00453
00454
00455 VeilLWLock = context0->lwlock;
00456 }
00457 else {
00458
00459 VeilLWLock = LWLockAssign();
00460 }
00461
00462
00463
00464 context0->lwlock = VeilLWLock;
00465 shared_meminfo->veil_lwlock = VeilLWLock;
00466
00467
00468 LWLockAcquire(VeilLWLock, LW_EXCLUSIVE);
00469 LWLockRelease(InitialLWLock);
00470
00471
00472
00473
00474 context1 = get_shmem_context("VEIL_SHMEM1", size, &found);
00475
00476
00477 context0->memctl = shared_meminfo;
00478 context1->memctl = shared_meminfo;
00479
00480
00481 shared_meminfo->type = OBJ_SHMEMCTL;
00482 shared_meminfo->current_context = 0;
00483 shared_meminfo->total_allocated[0] = size;
00484 shared_meminfo->total_allocated[1] = size;
00485 shared_meminfo->switching = false;
00486 shared_meminfo->context[0] = context0;
00487 shared_meminfo->context[1] = context1;
00488 shared_meminfo->xid[0] = GetCurrentTransactionId();
00489 shared_meminfo->xid[1] = shared_meminfo->xid[0];
00490 shared_meminfo->initialised = true;
00491
00492
00493 hash0 = get_hash0();
00494 hash1 = get_hash1();
00495
00496
00497 var = (VarEntry *) hash_search(hash0, (void *) "VEIL_SHMEMCTL",
00498 HASH_ENTER, &found);
00499
00500
00501 var->obj = (Object *) shared_meminfo;
00502 var->shared = true;
00503
00504 var = (VarEntry *) hash_search(hash0, (void *) "VEIL_SHMEMCTL",
00505 HASH_ENTER, &found);
00506
00507
00508 LWLockRelease(VeilLWLock);
00509 }
00510 }
00511 }
00512
00513
00514
00515
00516
00517
00518 HTAB *
00519 vl_get_shared_hash()
00520 {
00521 int context;
00522 HTAB *hash;
00523 static initialised = false;
00524
00525 if (!initialised) {
00526 (void) get_cur_context();
00527 initialised = true;
00528 }
00529
00530 context = get_cur_context_id();
00531
00532 if (context == 0) {
00533 hash = get_hash0();
00534 }
00535 else {
00536 hash = get_hash1();
00537 }
00538
00539 return hash;
00540 }
00541
00542
00543
00544
00545
00546
00547
00548 static void
00549 clear_hash(HTAB *hash)
00550 {
00551 static HASH_SEQ_STATUS status;
00552 VarEntry *var;
00553
00554 hash_seq_init(&status, hash);
00555 while (var = hash_seq_search(&status)) {
00556 if (strncmp("VEIL_SHMEMCTL", var->key, strlen("VEIL_SHMEMCTL")) != 0) {
00557 (void) hash_search(hash, var->key, HASH_REMOVE, NULL);
00558 }
00559 }
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 bool
00571 vl_prepare_context_switch()
00572 {
00573 int context_curidx;
00574 int context_newidx;
00575 HTAB *hash0 = get_hash0();
00576 HTAB *hash1 = get_hash1();
00577 TransactionId oldest_xid;
00578 MemContext *context;
00579
00580 (void) get_cur_context();
00581
00582 LWLockAcquire(VeilLWLock, LW_EXCLUSIVE);
00583
00584 if (shared_meminfo->switching) {
00585
00586 LWLockRelease(VeilLWLock);
00587 return false;
00588 }
00589
00590 shared_meminfo->switching = true;
00591
00592
00593
00594
00595 context_curidx = shared_meminfo->current_context;
00596 context_newidx = OTHER_CONTEXT(context_curidx);
00597
00598
00599
00600
00601 oldest_xid = GetOldestXmin(false);
00602 if (TransactionIdPrecedes(oldest_xid,
00603 shared_meminfo->xid[context_curidx]))
00604 {
00605
00606
00607
00608
00609 shared_meminfo->switching = false;
00610 LWLockRelease(VeilLWLock);
00611 return false;
00612 }
00613 else {
00614
00615
00616
00617 context = shared_meminfo->context[context_newidx];
00618 context->next = sizeof(MemContext);
00619
00620
00621
00622 if (context_newidx == 0) {
00623 context->next += sizeof(ShmemCtl);
00624 clear_hash(hash0);
00625 }
00626 else {
00627 clear_hash(hash1);
00628 }
00629 }
00630
00631 LWLockRelease(VeilLWLock);
00632 prepared_for_switch = true;
00633 return true;
00634 }
00635
00636
00637
00638
00639
00640
00641
00642 bool
00643 vl_complete_context_switch()
00644 {
00645 int context_curidx;
00646 int context_newidx;
00647
00648 if (!prepared_for_switch) {
00649 ereport(ERROR,
00650 (errcode(ERRCODE_INTERNAL_ERROR),
00651 errmsg("failed to complete context switch"),
00652 errdetail("Not prepared for switch - "
00653 "invalid state for operation")));
00654 }
00655
00656 LWLockAcquire(VeilLWLock, LW_EXCLUSIVE);
00657 context_curidx = shared_meminfo->current_context;
00658 context_newidx = OTHER_CONTEXT(context_curidx);
00659
00660 if (!shared_meminfo->switching) {
00661
00662 LWLockRelease(VeilLWLock);
00663
00664 ereport(ERROR,
00665 (errcode(ERRCODE_INTERNAL_ERROR),
00666 errmsg("failed to complete context switch"),
00667 errdetail("Session does not have switching set to true- "
00668 "invalid state for operation")));
00669 }
00670
00671 shared_meminfo->switching = false;
00672 shared_meminfo->current_context = context_newidx;
00673 shared_meminfo->xid[context_newidx] = GetCurrentTransactionId();
00674 LWLockRelease(VeilLWLock);
00675 prepared_for_switch = false;
00676 return true;
00677 }
00678
00679
00680
00681
00682
00683 void
00684 vl_force_context_switch()
00685 {
00686 int context_curidx;
00687 int context_newidx;
00688 MemContext *context;
00689 HTAB *hash0 = get_hash0();
00690 HTAB *hash1 = get_hash1();
00691
00692 (void) get_cur_context();
00693
00694 LWLockAcquire(VeilLWLock, LW_EXCLUSIVE);
00695
00696 context_curidx = shared_meminfo->current_context;
00697 context_newidx = OTHER_CONTEXT(context_curidx);
00698
00699
00700
00701 context = shared_meminfo->context[context_newidx];
00702 context->next = sizeof(MemContext);
00703
00704
00705
00706 if (context_newidx == 0) {
00707 context->next += sizeof(ShmemCtl);
00708 clear_hash(hash0);
00709 }
00710 else {
00711 clear_hash(hash1);
00712 }
00713
00714 shared_meminfo->switching = false;
00715 shared_meminfo->current_context = context_newidx;
00716 shared_meminfo->xid[context_newidx] = GetCurrentTransactionId();
00717 shared_meminfo->xid[0] = GetCurrentTransactionId();
00718 LWLockRelease(VeilLWLock);
00719 prepared_for_switch = false;
00720 }
00721
00722 #else
00723 #include "veil_shmem_pre82.inc"
00724
00725 #endif