30
30
* in a format that allows either forward or backward scan. Otherwise, only
31
31
* forward scan is allowed. A request for backward scan must be made before
32
32
* putting any tuples into the tuplestore. Rewind is normally allowed but
33
- * can be turned off via tuplestore_set_eflags; turning off both backward
34
- * scan and rewind for all read pointers enables truncation of the tuplestore
35
- * at the oldest read point for minimal memory usage.
33
+ * can be turned off via tuplestore_set_eflags; turning off rewind for all
34
+ * read pointers enables truncation of the tuplestore at the oldest read point
35
+ * for minimal memory usage. (The caller must explicitly call tuplestore_trim
36
+ * at appropriate times for truncation to actually happen.)
36
37
*
37
38
* Note: in TSS_WRITEFILE state, the temp file's seek position is the
38
39
* current write position, and the write-position variables in the tuplestore
46
47
* Portions Copyright (c) 1994, Regents of the University of California
47
48
*
48
49
* IDENTIFICATION
49
- * $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.43 2008/10/28 15:51:03 tgl Exp $
50
+ * $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.44 2008/12/27 17:39:00 tgl Exp $
50
51
*
51
52
*-------------------------------------------------------------------------
52
53
*/
@@ -101,6 +102,7 @@ struct Tuplestorestate
101
102
int eflags ; /* capability flags (OR of pointers' flags) */
102
103
bool backward ; /* store extra length words in file? */
103
104
bool interXact ; /* keep open through transactions? */
105
+ bool truncated ; /* tuplestore_trim has removed tuples? */
104
106
long availMem ; /* remaining memory available, in bytes */
105
107
BufFile * myfile ; /* underlying file, or NULL if none */
106
108
@@ -220,7 +222,6 @@ static Tuplestorestate *tuplestore_begin_common(int eflags,
220
222
int maxKBytes );
221
223
static void tuplestore_puttuple_common (Tuplestorestate * state , void * tuple );
222
224
static void dumptuples (Tuplestorestate * state );
223
- static void tuplestore_trim (Tuplestorestate * state );
224
225
static unsigned int getlen (Tuplestorestate * state , bool eofOK );
225
226
static void * copytup_heap (Tuplestorestate * state , void * tup );
226
227
static void writetup_heap (Tuplestorestate * state , void * tup );
@@ -242,6 +243,7 @@ tuplestore_begin_common(int eflags, bool interXact, int maxKBytes)
242
243
state -> status = TSS_INMEM ;
243
244
state -> eflags = eflags ;
244
245
state -> interXact = interXact ;
246
+ state -> truncated = false;
245
247
state -> availMem = maxKBytes * 1024L ;
246
248
state -> myfile = NULL ;
247
249
@@ -319,6 +321,10 @@ tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
319
321
* EXEC_FLAG_BACKWARD need backward fetch
320
322
* If tuplestore_set_eflags is not called, REWIND is allowed, and BACKWARD
321
323
* is set per "randomAccess" in the tuplestore_begin_xxx call.
324
+ *
325
+ * NOTE: setting BACKWARD without REWIND means the pointer can read backwards,
326
+ * but not further than the truncation point (the furthest-back read pointer
327
+ * position at the time of the last tuplestore_trim call).
322
328
*/
323
329
void
324
330
tuplestore_set_eflags (Tuplestorestate * state , int eflags )
@@ -397,6 +403,7 @@ tuplestore_clear(Tuplestorestate *state)
397
403
}
398
404
}
399
405
state -> status = TSS_INMEM ;
406
+ state -> truncated = false;
400
407
state -> memtupcount = 0 ;
401
408
readptr = state -> readptrs ;
402
409
for (i = 0 ; i < state -> readptrcount ; readptr ++ , i ++ )
@@ -723,12 +730,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
723
730
return NULL ;
724
731
if (readptr -> current < state -> memtupcount )
725
732
{
726
- /*
727
- * We have another tuple, so return it. Note: in
728
- * principle we could try tuplestore_trim() here after
729
- * advancing current, but this would cost cycles with
730
- * little chance of success, so we don't bother.
731
- */
733
+ /* We have another tuple, so return it */
732
734
return state -> memtuples [readptr -> current ++ ];
733
735
}
734
736
readptr -> eof_reached = true;
@@ -738,7 +740,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
738
740
{
739
741
/*
740
742
* if all tuples are fetched already then we return last
741
- * tuple, else - tuple before last returned.
743
+ * tuple, else tuple before last returned.
742
744
*/
743
745
if (readptr -> eof_reached )
744
746
{
@@ -748,11 +750,17 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
748
750
else
749
751
{
750
752
if (readptr -> current <= 0 )
753
+ {
754
+ Assert (!state -> truncated );
751
755
return NULL ;
756
+ }
752
757
readptr -> current -- ; /* last returned tuple */
753
758
}
754
759
if (readptr -> current <= 0 )
760
+ {
761
+ Assert (!state -> truncated );
755
762
return NULL ;
763
+ }
756
764
return state -> memtuples [readptr -> current - 1 ];
757
765
}
758
766
break ;
@@ -795,7 +803,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
795
803
* Backward.
796
804
*
797
805
* if all tuples are fetched already then we return last tuple,
798
- * else - tuple before last returned.
806
+ * else tuple before last returned.
799
807
*
800
808
* Back up to fetch previously-returned tuple's ending length
801
809
* word. If seek fails, assume we are at start of file.
@@ -805,6 +813,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
805
813
{
806
814
/* even a failed backwards fetch gets you out of eof state */
807
815
readptr -> eof_reached = false;
816
+ Assert (!state -> truncated );
808
817
return NULL ;
809
818
}
810
819
tuplen = getlen (state , false);
@@ -833,6 +842,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
833
842
- (long ) (tuplen + sizeof (unsigned int )),
834
843
SEEK_CUR ) != 0 )
835
844
elog (ERROR , "bogus tuple length in backward scan" );
845
+ Assert (!state -> truncated );
836
846
return NULL ;
837
847
}
838
848
tuplen = getlen (state , false);
@@ -887,7 +897,8 @@ tuplestore_gettupleslot(Tuplestorestate *state, bool forward,
887
897
* tuplestore_advance - exported function to adjust position without fetching
888
898
*
889
899
* We could optimize this case to avoid palloc/pfree overhead, but for the
890
- * moment it doesn't seem worthwhile.
900
+ * moment it doesn't seem worthwhile. (XXX this probably needs to be
901
+ * reconsidered given the needs of window functions.)
891
902
*/
892
903
bool
893
904
tuplestore_advance (Tuplestorestate * state , bool forward )
@@ -948,6 +959,7 @@ tuplestore_rescan(Tuplestorestate *state)
948
959
TSReadPointer * readptr = & state -> readptrs [state -> activeptr ];
949
960
950
961
Assert (readptr -> eflags & EXEC_FLAG_REWIND );
962
+ Assert (!state -> truncated );
951
963
952
964
switch (state -> status )
953
965
{
@@ -1006,10 +1018,8 @@ tuplestore_copy_read_pointer(Tuplestorestate *state,
1006
1018
switch (state -> status )
1007
1019
{
1008
1020
case TSS_INMEM :
1009
- /* We might be able to truncate the tuplestore */
1010
- tuplestore_trim (state );
1011
- break ;
1012
1021
case TSS_WRITEFILE :
1022
+ /* no work */
1013
1023
break ;
1014
1024
case TSS_READFILE :
1015
1025
/*
@@ -1053,19 +1063,27 @@ tuplestore_copy_read_pointer(Tuplestorestate *state,
1053
1063
1054
1064
/*
1055
1065
* tuplestore_trim - remove all no-longer-needed tuples
1066
+ *
1067
+ * Calling this function authorizes the tuplestore to delete all tuples
1068
+ * before the oldest read pointer, if no read pointer is marked as requiring
1069
+ * REWIND capability.
1070
+ *
1071
+ * Note: this is obviously safe if no pointer has BACKWARD capability either.
1072
+ * If a pointer is marked as BACKWARD but not REWIND capable, it means that
1073
+ * the pointer can be moved backward but not before the oldest other read
1074
+ * pointer.
1056
1075
*/
1057
- static void
1076
+ void
1058
1077
tuplestore_trim (Tuplestorestate * state )
1059
1078
{
1060
1079
int oldest ;
1061
1080
int nremove ;
1062
1081
int i ;
1063
1082
1064
1083
/*
1065
- * We can truncate the tuplestore if neither backward scan nor
1066
- * rewind capability are required by any read pointer.
1084
+ * Truncation is disallowed if any read pointer requires rewind capability.
1067
1085
*/
1068
- if (state -> eflags & ( EXEC_FLAG_BACKWARD | EXEC_FLAG_REWIND ) )
1086
+ if (state -> eflags & EXEC_FLAG_REWIND )
1069
1087
return ;
1070
1088
1071
1089
/*
@@ -1125,6 +1143,9 @@ tuplestore_trim(Tuplestorestate *state)
1125
1143
if (!state -> readptrs [i ].eof_reached )
1126
1144
state -> readptrs [i ].current -= nremove ;
1127
1145
}
1146
+
1147
+ /* mark tuplestore as truncated (used for Assert crosschecks only) */
1148
+ state -> truncated = true;
1128
1149
}
1129
1150
1130
1151
0 commit comments