@@ -428,7 +428,7 @@ ForgetPrivateRefCountEntry(PrivateRefCountEntry *ref)
428
428
)
429
429
430
430
431
- static Buffer ReadBuffer_common (SMgrRelation reln , char relpersistence ,
431
+ static Buffer ReadBuffer_common (SMgrRelation reln , char relpersistence , char relkind ,
432
432
ForkNumber forkNum , BlockNumber blockNum ,
433
433
ReadBufferMode mode , BufferAccessStrategy strategy ,
434
434
bool * hit );
@@ -458,6 +458,95 @@ static int buffertag_comparator(const void *p1, const void *p2);
458
458
static int ckpt_buforder_comparator (const void * pa , const void * pb );
459
459
static int ts_ckpt_progress_comparator (Datum a , Datum b , void * arg );
460
460
461
+ /* ----------------------------
462
+ * TODO Replace it somewhere. BEGIN.
463
+ * ----------------------------
464
+ */
465
+
466
+ typedef struct TempTableInfoData
467
+ {
468
+ RelFileNode rnode ; /* relfilenode of this temp table (hash key) */
469
+ BlockNumber main_nblocks ; /* number of blocks in the rel */
470
+ } TempTableInfoData ;
471
+
472
+ typedef TempTableInfoData * TempTableInfo ;
473
+
474
+ static HTAB * tempTableHashTab = NULL ; /* hash table for tracking temp table's length */
475
+
476
+ /*
477
+ * Creates the hash table for storing the actual length of temp tables
478
+ */
479
+ static void
480
+ create_temptableinfo_hashtable (void )
481
+ {
482
+ HASHCTL ctl ;
483
+
484
+ memset (& ctl , 0 , sizeof (ctl ));
485
+ ctl .keysize = sizeof (RelFileNode );
486
+ ctl .entrysize = sizeof (TempTableInfoData );
487
+
488
+ tempTableHashTab = hash_create ("Temp table's lengts" , 16 , & ctl ,
489
+ HASH_ELEM | HASH_BLOBS );
490
+ }
491
+
492
+ void
493
+ drop_temptableinfo_hashtable (void )
494
+ {
495
+ if (tempTableHashTab )
496
+ {
497
+ hash_destroy (tempTableHashTab );
498
+ tempTableHashTab = NULL ;
499
+ }
500
+ }
501
+
502
+ void
503
+ delete_temptableinfo_from_hashtable (RelFileNode rnode )
504
+ {
505
+ elog (DEBUG1 , "delete entry from tempTableHashTab" );
506
+
507
+ if (tempTableHashTab == NULL )
508
+ return ;
509
+
510
+ if (hash_search (tempTableHashTab ,
511
+ (void * ) & rnode ,
512
+ HASH_REMOVE , NULL ) == NULL )
513
+ elog (DEBUG1 , "tempTableHashTab has no entry to delete" );
514
+ }
515
+
516
+ void
517
+ insert_temptableinfo_hashtable (RelFileNode rnode , BlockNumber nblocks )
518
+ {
519
+ TempTableInfo tti ;
520
+ bool ttiIsFound ;
521
+ elog (DEBUG1 , "insert entry to tempTableHashTab, nblocks %u" , nblocks );
522
+ elog (DEBUG1 , "insert entry. spcNode %u, dbNode %u, relNode %u" ,rnode .spcNode , rnode .dbNode , rnode .relNode );
523
+
524
+ /* hash table must already exist, when we are rewriting temp rel */
525
+ if (tempTableHashTab == NULL )
526
+ {
527
+ //TODO add some check here.
528
+ return ;
529
+ }
530
+ /* Create a hash table entry for this temp table */
531
+ tti = (TempTableInfo ) hash_search (tempTableHashTab , & rnode ,
532
+ HASH_ENTER , & ttiIsFound );
533
+
534
+ if (!ttiIsFound )
535
+ {
536
+ elog (DEBUG1 , "tempTableHashTab entry is not found" );
537
+ }
538
+ else
539
+ {
540
+ elog (DEBUG1 , "tempTableHashTab entry is found. main_nblocks %u, nblocks %u" , tti -> main_nblocks , nblocks );
541
+ }
542
+ tti -> main_nblocks = nblocks ;
543
+ }
544
+
545
+ /* ----------------------------
546
+ * TODO Replace it somewhere. END.
547
+ * ----------------------------
548
+ */
549
+
461
550
462
551
/*
463
552
* ComputeIoConcurrency -- get the number of pages to prefetch for a given
@@ -662,6 +751,7 @@ ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
662
751
*/
663
752
pgstat_count_buffer_read (reln );
664
753
buf = ReadBuffer_common (reln -> rd_smgr , reln -> rd_rel -> relpersistence ,
754
+ reln -> rd_rel -> relkind ,
665
755
forkNum , blockNum , mode , strategy , & hit );
666
756
if (hit )
667
757
pgstat_count_buffer_hit (reln );
@@ -689,7 +779,7 @@ ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum,
689
779
690
780
Assert (InRecovery );
691
781
692
- return ReadBuffer_common (smgr , RELPERSISTENCE_PERMANENT , forkNum , blockNum ,
782
+ return ReadBuffer_common (smgr , RELPERSISTENCE_PERMANENT , RELKIND_UNKNOWN , forkNum , blockNum ,
693
783
mode , strategy , & hit );
694
784
}
695
785
@@ -711,15 +801,17 @@ ReadBufferWithoutRelcache2(SMgrRelation smgr, ForkNumber forkNum,
711
801
* *hit is set to true if the request was satisfied from shared buffer cache.
712
802
*/
713
803
static Buffer
714
- ReadBuffer_common (SMgrRelation smgr , char relpersistence , ForkNumber forkNum ,
715
- BlockNumber blockNum , ReadBufferMode mode ,
716
- BufferAccessStrategy strategy , bool * hit )
804
+ ReadBuffer_common (SMgrRelation smgr , char relpersistence , char relkind ,
805
+ ForkNumber forkNum , BlockNumber blockNum , ReadBufferMode mode ,
806
+ BufferAccessStrategy strategy , bool * hit )
717
807
{
718
808
BufferDesc * bufHdr ;
719
809
Block bufBlock ;
720
810
bool found ;
721
811
bool isExtend ;
722
812
bool isLocalBuf = SmgrIsTemp (smgr );
813
+ bool isTempTableMainFork = false;
814
+ TempTableInfo tti ;
723
815
724
816
* hit = false;
725
817
@@ -736,12 +828,70 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
736
828
isExtend );
737
829
738
830
/* Substitute proper block number if caller asked for P_NEW */
831
+
832
+ /*
833
+ * It's unnecessary to create a physical file for a local temp
834
+ * relation when all buffers can be kept in memory.
835
+ * Track actual number of blocks in tempTableHashTab and don't
836
+ * use smgrnblocks to compute it.
837
+ * Here we do all the work needed for cache initialization.
838
+ */
839
+ if (isLocalBuf
840
+ && relkind == RELKIND_RELATION
841
+ && forkNum == MAIN_FORKNUM )
842
+ {
843
+ bool ttiIsFound ;
844
+ RelFileNode rnode = smgr -> smgr_rnode .node ;
845
+
846
+ elog (DEBUG1 , "ReadBuffer_common. spcNode %u, dbNode %u, relNode %u" ,rnode .spcNode , rnode .dbNode , rnode .relNode );
847
+ /* use the flag instead of "if" constructions like above */
848
+ isTempTableMainFork = true;
849
+
850
+ /* Create hash table if it's the first call */
851
+ if (tempTableHashTab == NULL )
852
+ {
853
+ create_temptableinfo_hashtable ();
854
+ elog (DEBUG1 , "tempTableHashTab is created" );
855
+ }
856
+ /* Find or create a hash table entry for this temp table */
857
+ tti = (TempTableInfo ) hash_search (tempTableHashTab , & rnode ,
858
+ HASH_ENTER , & ttiIsFound );
859
+
860
+ /*
861
+ * If it's the first time we're going to extend rel,
862
+ * fill the cache entry with number of blocks = 0
863
+ */
864
+ if (!ttiIsFound )
865
+ {
866
+ elog (DEBUG1 , "tempTableHashTab entry is not found" );
867
+ /* tti->rnode already filled in */
868
+ tti -> main_nblocks = 0 ;
869
+ }
870
+ else
871
+ {
872
+ elog (DEBUG1 , "tempTableHashTab is found. nblocks %u" ,tti -> main_nblocks );
873
+ }
874
+
875
+ /* And finally fill up the smgr cache value */
876
+ smgr -> smgr_main_nblocks = tti -> main_nblocks ;
877
+ elog (DEBUG1 , "We're done with a cache entry. smgr->smgr_main_nblocks %u tti->main_nblocks %u" ,
878
+ smgr -> smgr_main_nblocks , tti -> main_nblocks );
879
+ }
880
+
739
881
if (isExtend )
740
- blockNum = smgrnblocks (smgr , forkNum );
882
+ {
883
+ if (isTempTableMainFork )
884
+ blockNum = smgr -> smgr_main_nblocks ;
885
+ else
886
+ blockNum = smgrnblocks (smgr , forkNum );
887
+
888
+ elog (DEBUG1 , "isExtend. blockNum %u smgr->smgr_main_nblocks %u" , blockNum , smgr -> smgr_main_nblocks );
889
+ }
741
890
742
891
if (isLocalBuf )
743
892
{
744
893
bufHdr = LocalBufferAlloc (smgr , forkNum , blockNum , & found );
894
+
745
895
if (found )
746
896
pgBufferUsage .local_blks_hit ++ ;
747
897
else
@@ -873,7 +1023,23 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
873
1023
/* new buffers are zero-filled */
874
1024
MemSet ((char * ) bufBlock , 0 , BLCKSZ );
875
1025
/* don't set checksum for all-zero page */
876
- smgrextend (smgr , forkNum , blockNum , (char * ) bufBlock , false);
1026
+
1027
+
1028
+ /* Do not extend physical file for temp tables while table fits
1029
+ * into temp_buffers cache. We'll do it on demand, when buffer
1030
+ * will be flushed out to disk.
1031
+ * NOTE Currently works only for plain tables.
1032
+ */
1033
+ if (isTempTableMainFork )
1034
+ {
1035
+ smgr -> smgr_main_nblocks ++ ;
1036
+ tti -> main_nblocks ++ ;
1037
+ }
1038
+ else
1039
+ smgrextend (smgr , forkNum , blockNum , (char * ) bufBlock , false);
1040
+
1041
+ elog (DEBUG1 , "isExtend 2. relnode %u smgr->smgr_main_nblocks %u" ,
1042
+ smgr -> smgr_rnode .node .relNode , smgr -> smgr_main_nblocks );
877
1043
878
1044
/*
879
1045
* NB: we're *not* doing a ScheduleBufferTagForWriteback here;
@@ -2784,6 +2950,31 @@ RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
2784
2950
/* Open it at the smgr level if not already done */
2785
2951
RelationOpenSmgr (relation );
2786
2952
2953
+ /* Handle temp tables separately */
2954
+ if (SmgrIsTemp (relation -> rd_smgr )
2955
+ && forkNum == MAIN_FORKNUM
2956
+ && relation -> rd_rel -> relkind == RELKIND_RELATION )
2957
+ {
2958
+ TempTableInfo tti ;
2959
+ bool ttiIsFound ;
2960
+ RelFileNode rnode = relation -> rd_smgr -> smgr_rnode .node ;
2961
+
2962
+ /* If we have no hash table, the relation is definitely new and empty. */
2963
+ if (tempTableHashTab == NULL )
2964
+ return 0 ;
2965
+
2966
+ tti = (TempTableInfo ) hash_search (tempTableHashTab , & rnode ,
2967
+ HASH_FIND , & ttiIsFound );
2968
+ if (!ttiIsFound )
2969
+ {
2970
+ elog (DEBUG1 , "No cache entry for this temp relation" );
2971
+ // /* It's essential to fill the entry here */
2972
+ // tti->main_nblocks = 0;
2973
+ return 0 ;
2974
+ }
2975
+ else
2976
+ return tti -> main_nblocks ;
2977
+ }
2787
2978
return smgrnblocks (relation -> rd_smgr , forkNum );
2788
2979
}
2789
2980
0 commit comments