|
62 | 62 | #define BUF_WRITTEN 0x01
|
63 | 63 | #define BUF_REUSABLE 0x02
|
64 | 64 |
|
| 65 | +#define DROP_RELS_BSEARCH_THRESHOLD 20 |
65 | 66 |
|
66 | 67 | /* GUC variables */
|
67 | 68 | bool zero_damaged_pages = false;
|
@@ -107,6 +108,7 @@ static volatile BufferDesc *BufferAlloc(SMgrRelation smgr,
|
107 | 108 | bool *foundPtr);
|
108 | 109 | static void FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln);
|
109 | 110 | static void AtProcExit_Buffers(int code, Datum arg);
|
| 111 | +static int rnode_comparator(const void *p1, const void *p2); |
110 | 112 |
|
111 | 113 |
|
112 | 114 | /*
|
@@ -2086,43 +2088,103 @@ DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber forkNum,
|
2086 | 2088 | }
|
2087 | 2089 |
|
2088 | 2090 | /* ---------------------------------------------------------------------
|
2089 |
| - * DropRelFileNodeAllBuffers |
| 2091 | + * DropRelFileNodesAllBuffers |
2090 | 2092 | *
|
2091 | 2093 | * This function removes from the buffer pool all the pages of all
|
2092 |
| - * forks of the specified relation. It's equivalent to calling |
2093 |
| - * DropRelFileNodeBuffers once per fork with firstDelBlock = 0. |
| 2094 | + * forks of the specified relations. It's equivalent to calling |
| 2095 | + * DropRelFileNodeBuffers once per fork per relation with |
| 2096 | + * firstDelBlock = 0. |
2094 | 2097 | * --------------------------------------------------------------------
|
2095 | 2098 | */
|
2096 | 2099 | void
|
2097 |
| -DropRelFileNodeAllBuffers(RelFileNodeBackend rnode) |
| 2100 | +DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes) |
2098 | 2101 | {
|
2099 |
| - int i; |
| 2102 | + int i, |
| 2103 | + n = 0; |
| 2104 | + RelFileNode *nodes; |
| 2105 | + bool use_bsearch; |
| 2106 | + |
| 2107 | + if (nnodes == 0) |
| 2108 | + return; |
| 2109 | + |
| 2110 | + nodes = palloc(sizeof(RelFileNode) * nnodes); /* non-local relations */ |
2100 | 2111 |
|
2101 | 2112 | /* If it's a local relation, it's localbuf.c's problem. */
|
2102 |
| - if (RelFileNodeBackendIsTemp(rnode)) |
| 2113 | + for (i = 0; i < nnodes; i++) |
2103 | 2114 | {
|
2104 |
| - if (rnode.backend == MyBackendId) |
2105 |
| - DropRelFileNodeAllLocalBuffers(rnode.node); |
| 2115 | + if (RelFileNodeBackendIsTemp(rnodes[i])) |
| 2116 | + { |
| 2117 | + if (rnodes[i].backend == MyBackendId) |
| 2118 | + DropRelFileNodeAllLocalBuffers(rnodes[i].node); |
| 2119 | + } |
| 2120 | + else |
| 2121 | + nodes[n++] = rnodes[i].node; |
| 2122 | + } |
| 2123 | + |
| 2124 | + /* |
| 2125 | + * If there are no non-local relations, then we're done. Release the memory |
| 2126 | + * and return. |
| 2127 | + */ |
| 2128 | + if (n == 0) |
| 2129 | + { |
| 2130 | + pfree(nodes); |
2106 | 2131 | return;
|
2107 | 2132 | }
|
2108 | 2133 |
|
| 2134 | + /* |
| 2135 | + * For low number of relations to drop just use a simple walk through, to |
| 2136 | + * save the bsearch overhead. The threshold to use is rather a guess than a |
| 2137 | + * exactly determined value, as it depends on many factors (CPU and RAM |
| 2138 | + * speeds, amount of shared buffers etc.). |
| 2139 | + */ |
| 2140 | + use_bsearch = n > DROP_RELS_BSEARCH_THRESHOLD; |
| 2141 | + |
| 2142 | + /* sort the list of rnodes if necessary */ |
| 2143 | + if (use_bsearch) |
| 2144 | + pg_qsort(nodes, n, sizeof(RelFileNode), rnode_comparator); |
| 2145 | + |
2109 | 2146 | for (i = 0; i < NBuffers; i++)
|
2110 | 2147 | {
|
| 2148 | + RelFileNode *rnode = NULL; |
2111 | 2149 | volatile BufferDesc *bufHdr = &BufferDescriptors[i];
|
2112 | 2150 |
|
2113 | 2151 | /*
|
2114 | 2152 | * As in DropRelFileNodeBuffers, an unlocked precheck should be safe
|
2115 | 2153 | * and saves some cycles.
|
2116 | 2154 | */
|
2117 |
| - if (!RelFileNodeEquals(bufHdr->tag.rnode, rnode.node)) |
| 2155 | + |
| 2156 | + if (!use_bsearch) |
| 2157 | + { |
| 2158 | + int j; |
| 2159 | + |
| 2160 | + for (j = 0; j < n; j++) |
| 2161 | + { |
| 2162 | + if (RelFileNodeEquals(bufHdr->tag.rnode, nodes[j])) |
| 2163 | + { |
| 2164 | + rnode = &nodes[j]; |
| 2165 | + break; |
| 2166 | + } |
| 2167 | + } |
| 2168 | + } |
| 2169 | + else |
| 2170 | + { |
| 2171 | + rnode = bsearch((const void *) &(bufHdr->tag.rnode), |
| 2172 | + nodes, n, sizeof(RelFileNode), |
| 2173 | + rnode_comparator); |
| 2174 | + } |
| 2175 | + |
| 2176 | + /* buffer doesn't belong to any of the given relfilenodes; skip it */ |
| 2177 | + if (rnode == NULL) |
2118 | 2178 | continue;
|
2119 | 2179 |
|
2120 | 2180 | LockBufHdr(bufHdr);
|
2121 |
| - if (RelFileNodeEquals(bufHdr->tag.rnode, rnode.node)) |
| 2181 | + if (RelFileNodeEquals(bufHdr->tag.rnode, (*rnode))) |
2122 | 2182 | InvalidateBuffer(bufHdr); /* releases spinlock */
|
2123 | 2183 | else
|
2124 | 2184 | UnlockBufHdr(bufHdr);
|
2125 | 2185 | }
|
| 2186 | + |
| 2187 | + pfree(nodes); |
2126 | 2188 | }
|
2127 | 2189 |
|
2128 | 2190 | /* ---------------------------------------------------------------------
|
@@ -2953,3 +3015,30 @@ local_buffer_write_error_callback(void *arg)
|
2953 | 3015 | pfree(path);
|
2954 | 3016 | }
|
2955 | 3017 | }
|
| 3018 | + |
| 3019 | +/* |
| 3020 | + * RelFileNode qsort/bsearch comparator; see RelFileNodeEquals. |
| 3021 | + */ |
| 3022 | +static int |
| 3023 | +rnode_comparator(const void *p1, const void *p2) |
| 3024 | +{ |
| 3025 | + RelFileNode n1 = *(RelFileNode *) p1; |
| 3026 | + RelFileNode n2 = *(RelFileNode *) p2; |
| 3027 | + |
| 3028 | + if (n1.relNode < n2.relNode) |
| 3029 | + return -1; |
| 3030 | + else if (n1.relNode > n2.relNode) |
| 3031 | + return 1; |
| 3032 | + |
| 3033 | + if (n1.dbNode < n2.dbNode) |
| 3034 | + return -1; |
| 3035 | + else if (n1.dbNode > n2.dbNode) |
| 3036 | + return 1; |
| 3037 | + |
| 3038 | + if (n1.spcNode < n2.spcNode) |
| 3039 | + return -1; |
| 3040 | + else if (n1.spcNode > n2.spcNode) |
| 3041 | + return 1; |
| 3042 | + else |
| 3043 | + return 0; |
| 3044 | +} |
0 commit comments