8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.67 2003/09/02 18:13:29 tgl Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.68 2003/09/04 22:06:27 tgl Exp $
12
12
*
13
13
* NOTES
14
14
* This file contains only the public interface routines.
27
27
#include "miscadmin.h"
28
28
29
29
30
- bool BuildingHash = false;
31
-
32
-
33
30
/* Working state for hashbuild and its callback */
34
31
typedef struct
35
32
{
@@ -61,9 +58,6 @@ hashbuild(PG_FUNCTION_ARGS)
61
58
double reltuples ;
62
59
HashBuildState buildstate ;
63
60
64
- /* set flag to disable locking */
65
- BuildingHash = true;
66
-
67
61
/*
68
62
* We expect to be called exactly once for any index relation. If
69
63
* that's not the case, big trouble's what we have.
@@ -82,9 +76,6 @@ hashbuild(PG_FUNCTION_ARGS)
82
76
reltuples = IndexBuildHeapScan (heap , index , indexInfo ,
83
77
hashbuildCallback , (void * ) & buildstate );
84
78
85
- /* all done */
86
- BuildingHash = false;
87
-
88
79
/*
89
80
* Since we just counted the tuples in the heap, we update its stats
90
81
* in pg_class to guarantee that the planner takes advantage of the
@@ -212,10 +203,18 @@ hashgettuple(PG_FUNCTION_ARGS)
212
203
IndexScanDesc scan = (IndexScanDesc ) PG_GETARG_POINTER (0 );
213
204
ScanDirection dir = (ScanDirection ) PG_GETARG_INT32 (1 );
214
205
HashScanOpaque so = (HashScanOpaque ) scan -> opaque ;
206
+ Relation rel = scan -> indexRelation ;
215
207
Page page ;
216
208
OffsetNumber offnum ;
217
209
bool res ;
218
210
211
+ /*
212
+ * We hold pin but not lock on current buffer while outside the hash AM.
213
+ * Reacquire the read lock here.
214
+ */
215
+ if (BufferIsValid (so -> hashso_curbuf ))
216
+ _hash_chgbufaccess (rel , so -> hashso_curbuf , HASH_NOLOCK , HASH_READ );
217
+
219
218
/*
220
219
* If we've already initialized this scan, we can just advance it in
221
220
* the appropriate direction. If we haven't done so yet, we call a
@@ -267,6 +266,10 @@ hashgettuple(PG_FUNCTION_ARGS)
267
266
}
268
267
}
269
268
269
+ /* Release read lock on current buffer, but keep it pinned */
270
+ if (BufferIsValid (so -> hashso_curbuf ))
271
+ _hash_chgbufaccess (rel , so -> hashso_curbuf , HASH_READ , HASH_NOLOCK );
272
+
270
273
PG_RETURN_BOOL (res );
271
274
}
272
275
@@ -285,6 +288,8 @@ hashbeginscan(PG_FUNCTION_ARGS)
285
288
286
289
scan = RelationGetIndexScan (rel , keysz , scankey );
287
290
so = (HashScanOpaque ) palloc (sizeof (HashScanOpaqueData ));
291
+ so -> hashso_bucket_valid = false;
292
+ so -> hashso_bucket_blkno = 0 ;
288
293
so -> hashso_curbuf = so -> hashso_mrkbuf = InvalidBuffer ;
289
294
scan -> opaque = so ;
290
295
@@ -303,28 +308,38 @@ hashrescan(PG_FUNCTION_ARGS)
303
308
IndexScanDesc scan = (IndexScanDesc ) PG_GETARG_POINTER (0 );
304
309
ScanKey scankey = (ScanKey ) PG_GETARG_POINTER (1 );
305
310
HashScanOpaque so = (HashScanOpaque ) scan -> opaque ;
306
- ItemPointer iptr ;
311
+ Relation rel = scan -> indexRelation ;
307
312
308
- /* we hold a read lock on the current page in the scan */
309
- if (ItemPointerIsValid ( iptr = & ( scan -> currentItemData )) )
313
+ /* if we are called from beginscan, so is still NULL */
314
+ if (so )
310
315
{
311
- _hash_relbuf (scan -> indexRelation , so -> hashso_curbuf , HASH_READ );
316
+ /* release any pins we still hold */
317
+ if (BufferIsValid (so -> hashso_curbuf ))
318
+ _hash_dropbuf (rel , so -> hashso_curbuf );
312
319
so -> hashso_curbuf = InvalidBuffer ;
313
- ItemPointerSetInvalid (iptr );
314
- }
315
- if (ItemPointerIsValid (iptr = & (scan -> currentMarkData )))
316
- {
317
- _hash_relbuf (scan -> indexRelation , so -> hashso_mrkbuf , HASH_READ );
320
+
321
+ if (BufferIsValid (so -> hashso_mrkbuf ))
322
+ _hash_dropbuf (rel , so -> hashso_mrkbuf );
318
323
so -> hashso_mrkbuf = InvalidBuffer ;
319
- ItemPointerSetInvalid (iptr );
324
+
325
+ /* release lock on bucket, too */
326
+ if (so -> hashso_bucket_blkno )
327
+ _hash_droplock (rel , so -> hashso_bucket_blkno , HASH_SHARE );
328
+ so -> hashso_bucket_blkno = 0 ;
320
329
}
321
330
331
+ /* set positions invalid (this will cause _hash_first call) */
332
+ ItemPointerSetInvalid (& (scan -> currentItemData ));
333
+ ItemPointerSetInvalid (& (scan -> currentMarkData ));
334
+
322
335
/* Update scan key, if a new one is given */
323
336
if (scankey && scan -> numberOfKeys > 0 )
324
337
{
325
338
memmove (scan -> keyData ,
326
339
scankey ,
327
340
scan -> numberOfKeys * sizeof (ScanKeyData ));
341
+ if (so )
342
+ so -> hashso_bucket_valid = false;
328
343
}
329
344
330
345
PG_RETURN_VOID ();
@@ -337,32 +352,32 @@ Datum
337
352
hashendscan (PG_FUNCTION_ARGS )
338
353
{
339
354
IndexScanDesc scan = (IndexScanDesc ) PG_GETARG_POINTER (0 );
340
- ItemPointer iptr ;
341
- HashScanOpaque so ;
355
+ HashScanOpaque so = ( HashScanOpaque ) scan -> opaque ;
356
+ Relation rel = scan -> indexRelation ;
342
357
343
- so = (HashScanOpaque ) scan -> opaque ;
358
+ /* don't need scan registered anymore */
359
+ _hash_dropscan (scan );
344
360
345
- /* release any locks we still hold */
346
- if (ItemPointerIsValid (iptr = & (scan -> currentItemData )))
347
- {
348
- _hash_relbuf (scan -> indexRelation , so -> hashso_curbuf , HASH_READ );
349
- so -> hashso_curbuf = InvalidBuffer ;
350
- ItemPointerSetInvalid (iptr );
351
- }
361
+ /* release any pins we still hold */
362
+ if (BufferIsValid (so -> hashso_curbuf ))
363
+ _hash_dropbuf (rel , so -> hashso_curbuf );
364
+ so -> hashso_curbuf = InvalidBuffer ;
352
365
353
- if (ItemPointerIsValid (iptr = & (scan -> currentMarkData )))
354
- {
355
- if (BufferIsValid (so -> hashso_mrkbuf ))
356
- _hash_relbuf (scan -> indexRelation , so -> hashso_mrkbuf , HASH_READ );
357
- so -> hashso_mrkbuf = InvalidBuffer ;
358
- ItemPointerSetInvalid (iptr );
359
- }
366
+ if (BufferIsValid (so -> hashso_mrkbuf ))
367
+ _hash_dropbuf (rel , so -> hashso_mrkbuf );
368
+ so -> hashso_mrkbuf = InvalidBuffer ;
360
369
361
- /* don't need scan registered anymore */
362
- _hash_dropscan (scan );
370
+ /* release lock on bucket, too */
371
+ if (so -> hashso_bucket_blkno )
372
+ _hash_droplock (rel , so -> hashso_bucket_blkno , HASH_SHARE );
373
+ so -> hashso_bucket_blkno = 0 ;
363
374
364
375
/* be tidy */
365
- pfree (scan -> opaque );
376
+ ItemPointerSetInvalid (& (scan -> currentItemData ));
377
+ ItemPointerSetInvalid (& (scan -> currentMarkData ));
378
+
379
+ pfree (so );
380
+ scan -> opaque = NULL ;
366
381
367
382
PG_RETURN_VOID ();
368
383
}
@@ -374,25 +389,21 @@ Datum
374
389
hashmarkpos (PG_FUNCTION_ARGS )
375
390
{
376
391
IndexScanDesc scan = (IndexScanDesc ) PG_GETARG_POINTER (0 );
377
- ItemPointer iptr ;
378
- HashScanOpaque so ;
379
-
380
- so = (HashScanOpaque ) scan -> opaque ;
392
+ HashScanOpaque so = (HashScanOpaque ) scan -> opaque ;
393
+ Relation rel = scan -> indexRelation ;
381
394
382
- /* release lock on old marked data, if any */
383
- if (ItemPointerIsValid (iptr = & (scan -> currentMarkData )))
384
- {
385
- _hash_relbuf (scan -> indexRelation , so -> hashso_mrkbuf , HASH_READ );
386
- so -> hashso_mrkbuf = InvalidBuffer ;
387
- ItemPointerSetInvalid (iptr );
388
- }
395
+ /* release pin on old marked data, if any */
396
+ if (BufferIsValid (so -> hashso_mrkbuf ))
397
+ _hash_dropbuf (rel , so -> hashso_mrkbuf );
398
+ so -> hashso_mrkbuf = InvalidBuffer ;
399
+ ItemPointerSetInvalid (& (scan -> currentMarkData ));
389
400
390
- /* bump lock on currentItemData and copy to currentMarkData */
401
+ /* bump pin count on currentItemData and copy to currentMarkData */
391
402
if (ItemPointerIsValid (& (scan -> currentItemData )))
392
403
{
393
- so -> hashso_mrkbuf = _hash_getbuf (scan -> indexRelation ,
404
+ so -> hashso_mrkbuf = _hash_getbuf (rel ,
394
405
BufferGetBlockNumber (so -> hashso_curbuf ),
395
- HASH_READ );
406
+ HASH_NOLOCK );
396
407
scan -> currentMarkData = scan -> currentItemData ;
397
408
}
398
409
@@ -406,26 +417,21 @@ Datum
406
417
hashrestrpos (PG_FUNCTION_ARGS )
407
418
{
408
419
IndexScanDesc scan = (IndexScanDesc ) PG_GETARG_POINTER (0 );
409
- ItemPointer iptr ;
410
- HashScanOpaque so ;
420
+ HashScanOpaque so = ( HashScanOpaque ) scan -> opaque ;
421
+ Relation rel = scan -> indexRelation ;
411
422
412
- so = (HashScanOpaque ) scan -> opaque ;
423
+ /* release pin on current data, if any */
424
+ if (BufferIsValid (so -> hashso_curbuf ))
425
+ _hash_dropbuf (rel , so -> hashso_curbuf );
426
+ so -> hashso_curbuf = InvalidBuffer ;
427
+ ItemPointerSetInvalid (& (scan -> currentItemData ));
413
428
414
- /* release lock on current data, if any */
415
- if (ItemPointerIsValid (iptr = & (scan -> currentItemData )))
416
- {
417
- _hash_relbuf (scan -> indexRelation , so -> hashso_curbuf , HASH_READ );
418
- so -> hashso_curbuf = InvalidBuffer ;
419
- ItemPointerSetInvalid (iptr );
420
- }
421
-
422
- /* bump lock on currentMarkData and copy to currentItemData */
429
+ /* bump pin count on currentMarkData and copy to currentItemData */
423
430
if (ItemPointerIsValid (& (scan -> currentMarkData )))
424
431
{
425
- so -> hashso_curbuf = _hash_getbuf (scan -> indexRelation ,
432
+ so -> hashso_curbuf = _hash_getbuf (rel ,
426
433
BufferGetBlockNumber (so -> hashso_mrkbuf ),
427
- HASH_READ );
428
-
434
+ HASH_NOLOCK );
429
435
scan -> currentItemData = scan -> currentMarkData ;
430
436
}
431
437
@@ -474,7 +480,7 @@ hashbulkdelete(PG_FUNCTION_ARGS)
474
480
orig_maxbucket = metap -> hashm_maxbucket ;
475
481
orig_ntuples = metap -> hashm_ntuples ;
476
482
memcpy (& local_metapage , metap , sizeof (local_metapage ));
477
- _hash_relbuf (rel , metabuf , HASH_READ );
483
+ _hash_relbuf (rel , metabuf );
478
484
479
485
/* Scan the buckets that we know exist */
480
486
cur_bucket = 0 ;
@@ -490,7 +496,12 @@ hashbulkdelete(PG_FUNCTION_ARGS)
490
496
/* Get address of bucket's start page */
491
497
bucket_blkno = BUCKET_TO_BLKNO (& local_metapage , cur_bucket );
492
498
493
- /* XXX lock bucket here */
499
+ /* Exclusive-lock the bucket so we can shrink it */
500
+ _hash_getlock (rel , bucket_blkno , HASH_EXCLUSIVE );
501
+
502
+ /* Shouldn't have any active scans locally, either */
503
+ if (_hash_has_active_scan (rel , cur_bucket ))
504
+ elog (ERROR , "hash index has active scan during VACUUM" );
494
505
495
506
/* Scan each page in bucket */
496
507
blkno = bucket_blkno ;
@@ -522,13 +533,6 @@ hashbulkdelete(PG_FUNCTION_ARGS)
522
533
htup = & (hitem -> hash_itup .t_tid );
523
534
if (callback (htup , callback_state ))
524
535
{
525
- ItemPointerData indextup ;
526
-
527
- /* adjust any active scans that will be affected */
528
- /* (this should be unnecessary) */
529
- ItemPointerSet (& indextup , blkno , offno );
530
- _hash_adjscans (rel , & indextup );
531
-
532
536
/* delete the item from the page */
533
537
PageIndexTupleDelete (page , offno );
534
538
bucket_dirty = page_dirty = true;
@@ -547,24 +551,22 @@ hashbulkdelete(PG_FUNCTION_ARGS)
547
551
}
548
552
549
553
/*
550
- * Write or free page if needed, advance to next page. We want
551
- * to preserve the invariant that overflow pages are nonempty.
554
+ * Write page if needed, advance to next page.
552
555
*/
553
556
blkno = opaque -> hasho_nextblkno ;
554
557
555
- if (PageIsEmpty (page ) && (opaque -> hasho_flag & LH_OVERFLOW_PAGE ))
556
- _hash_freeovflpage (rel , buf );
557
- else if (page_dirty )
558
+ if (page_dirty )
558
559
_hash_wrtbuf (rel , buf );
559
560
else
560
- _hash_relbuf (rel , buf , HASH_WRITE );
561
+ _hash_relbuf (rel , buf );
561
562
}
562
563
563
564
/* If we deleted anything, try to compact free space */
564
565
if (bucket_dirty )
565
566
_hash_squeezebucket (rel , cur_bucket , bucket_blkno );
566
567
567
- /* XXX unlock bucket here */
568
+ /* Release bucket lock */
569
+ _hash_droplock (rel , bucket_blkno , HASH_EXCLUSIVE );
568
570
569
571
/* Advance to next bucket */
570
572
cur_bucket ++ ;
@@ -580,7 +582,7 @@ hashbulkdelete(PG_FUNCTION_ARGS)
580
582
/* There's been a split, so process the additional bucket(s) */
581
583
cur_maxbucket = metap -> hashm_maxbucket ;
582
584
memcpy (& local_metapage , metap , sizeof (local_metapage ));
583
- _hash_relbuf (rel , metabuf , HASH_WRITE );
585
+ _hash_relbuf (rel , metabuf );
584
586
goto loop_top ;
585
587
}
586
588
0 commit comments