Hi, 2008/10/1 Dimitri Fontaine <[EMAIL PROTECTED]>: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Hi, > > Le 30 sept. 08 à 20:03, Tom Lane a écrit : >> >> set_read_position(tupstore, &local_read_position); >> tuple = tuplestore_gettuple(tupstore, ...); >> get_read_position(tupstore, &local_read_position); >> >> rather than just tuplestore_gettuple. The set/get functions will be >> cheap enough that this is no big deal. (Or maybe we should just >> provide a wrapper function that does this sequence?) > > It seems to me to share some ideas with the MemoryContext concept: what > about a TupstoreContext associated with tuplestore, you get a common default > one if you don't register your own, and use > tuplestore_gettuple(MyTupstoreContext, ...); > > Maybe some other API would benefit from the idea? >
I'm just working on tuplestore recording multiple positions for my window function project. Attached patch is still in progress but seems it works in a situation. From my work, the setting/getting read position and delegate savig positions to the caller will probably have problems, because of memory control for saving positions and tuplestore status changing (memory -> BufFile). Instead, I decided it'd better that we can indicate the row number by integer. Regards, -- Hitoshi Harada
*** a/src/backend/utils/sort/tuplestore.c --- b/src/backend/utils/sort/tuplestore.c *************** *** 141,148 **** struct Tuplestorestate --- 141,159 ---- int markpos_current; /* saved "current" */ int markpos_file; /* saved "readpos_file" */ off_t markpos_offset; /* saved "readpos_offset" */ + + /* + * When asked EXEC_FLAG_SETPOS, we need record multiple state->myfile pointer. + * This pointer is used to optimize offset calculation closer to O(1). + * npos_file is fixed layout file since only int + off_t will be needed to restore + * tuple positions. int + off_t may get better by struct{int, off_t} to reduce call + * BufFileWrite and BufFileRead? + * This feature is off unless eflags is set. + */ + BufFile *npos_file; }; + #define COPYTUP(state,tup) ((*(state)->copytup) (state, tup)) #define WRITETUP(state,tup) ((*(state)->writetup) (state, tup)) #define READTUP(state,len) ((*(state)->readtup) (state, len)) *************** *** 150,155 **** struct Tuplestorestate --- 161,175 ---- #define USEMEM(state,amt) ((state)->availMem -= (amt)) #define FREEMEM(state,amt) ((state)->availMem += (amt)) + #define RecordFilePointer(state,file,offset) do{\ + BufFileTell((state)->myfile, \ + &(file), &(offset)); \ + BufFileWrite((state)->npos_file, \ + &(file), sizeof(int)); \ + BufFileWrite((state)->npos_file, \ + &(offset), sizeof(off_t)); \ + }while(0) + /*-------------------- * * NOTES about on-tape representation of tuples: *************** *** 200,205 **** static Tuplestorestate *tuplestore_begin_common(int eflags, --- 220,226 ---- int maxKBytes); static void tuplestore_puttuple_common(Tuplestorestate *state, void *tuple); static void dumptuples(Tuplestorestate *state); + static void tuplestore_recordpos(Tuplestorestate *state); static void tuplestore_trim(Tuplestorestate *state, int ntuples); static unsigned int getlen(Tuplestorestate *state, bool eofOK); static void *copytup_heap(Tuplestorestate *state, void *tup); *************** *** 234,239 **** tuplestore_begin_common(int eflags, bool interXact, int maxKBytes) --- 255,262 ---- state->eof_reached = false; state->current = 0; + state->npos_file = NULL; + return state; } *************** *** 291,296 **** tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes) --- 314,320 ---- * EXEC_FLAG_REWIND need rewind to start * EXEC_FLAG_BACKWARD need backward fetch * EXEC_FLAG_MARK need mark/restore + * EXEC_FLAG_SETPOS need setpos * If tuplestore_set_eflags is not called, REWIND and MARK are allowed, * and BACKWARD is set per "randomAccess" in the tuplestore_begin_xxx call. */ *************** *** 315,320 **** tuplestore_end(Tuplestorestate *state) --- 339,346 ---- if (state->myfile) BufFileClose(state->myfile); + if (state->npos_file) + BufFileClose(state->npos_file); if (state->memtuples) { for (i = 0; i < state->memtupcount; i++) *************** *** 443,452 **** tuplestore_puttuple_common(Tuplestorestate *state, void *tuple) --- 469,481 ---- */ PrepareTempTablespaces(); state->myfile = BufFileCreateTemp(state->interXact); + if (state->eflags & EXEC_FLAG_SETPOS) + state->npos_file = BufFileCreateTemp(state->interXact); state->status = TSS_WRITEFILE; dumptuples(state); break; case TSS_WRITEFILE: + tuplestore_recordpos(state); WRITETUP(state, tuple); break; case TSS_READFILE: *************** *** 461,466 **** tuplestore_puttuple_common(Tuplestorestate *state, void *tuple) --- 490,496 ---- state->writepos_file, state->writepos_offset, SEEK_SET) != 0) elog(ERROR, "seek to EOF failed"); + tuplestore_recordpos(state); state->status = TSS_WRITEFILE; WRITETUP(state, tuple); break; *************** *** 678,683 **** static void --- 708,715 ---- dumptuples(Tuplestorestate *state) { int i; + int file; + off_t offset; for (i = 0;; i++) { *************** *** 687,692 **** dumptuples(Tuplestorestate *state) --- 719,730 ---- if (i == state->markpos_current) BufFileTell(state->myfile, &state->markpos_file, &state->markpos_offset); + + if (state->npos_file) + { + RecordFilePointer(state, file, offset); + } + if (i >= state->memtupcount) break; WRITETUP(state, state->memtuples[i]); *************** *** 812,817 **** tuplestore_restorepos(Tuplestorestate *state) --- 850,931 ---- } /* + * tuplestore_setpos - + */ + void + tuplestore_setpos(Tuplestorestate *state, int nth) + { + int file, file_npos; + off_t offset, offset_npos; + + Assert((state->eflags & EXEC_FLAG_SETPOS) && (0 <= nth)); + + switch (state->status) + { + case TSS_INMEM: + state->eof_reached = false; + state->current = nth; + break; + case TSS_WRITEFILE: + case TSS_READFILE: + /* + * It is quite redundant and may have to be optimized not to + * read buffer back and force. But we don't know if we call + * setpos so frequently. + */ + state->eof_reached = false; + BufFileTell(state->npos_file, + &file_npos, &offset_npos); + if (!( + (BufFileSeekBlock(state->npos_file, + nth * (sizeof(int) + sizeof(off_t)) / BLCKSZ) == 0) && + (BufFileSeek(state->npos_file, 0, + nth * (sizeof(int) + sizeof(off_t)) % BLCKSZ, + SEEK_CUR) == 0) && + (BufFileRead(state->npos_file, + &file, sizeof(int)) == 0) && + (BufFileRead(state->npos_file, + &offset, sizeof(off_t)) == 0) && + (BufFileSeek(state->npos_file, + file_npos, offset_npos, SEEK_SET) == 0))) + elog(ERROR, "tuplestore_setpos failed while seeking for tuple position"); + + if (state->status == TSS_WRITEFILE) + { + state->readpos_file = file; + state->readpos_offset = offset; + } + else + { + if (BufFileSeek(state->myfile, + file, offset, SEEK_SET) != 0) + elog(ERROR, "tuplestore_setpos failed"); + } + break; + default: + elog(ERROR, "invalid tuplestore state"); + break; + } + } + + /* + * + */ + static void + tuplestore_recordpos(Tuplestorestate *state) + { + int file; + off_t offset; + + Assert(state->status != TSS_INMEM); + + if (!state->npos_file) + return; + + RecordFilePointer(state, file, offset); + } + + /* * tuplestore_trim - remove all but ntuples tuples before current */ static void
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers