public final class ParserPool extends Object
TGSqlParser per EDbVendor.
Allocating a new TGSqlParser is non-trivial (vendor parser
factory wiring, lexer state, license initialisation). For a script with N
statement regions, the engine wants to perform up to N parse attempts
without paying allocation cost per region. ParserPool hands out
the same instance every time after a lazy first allocation, and provides
an explicit reset() for the engine to call between regions.
"Size-1" is the plan's mandate (§5.3, §7.3/S12). The pool is therefore
single-threaded by construction — a single ParseRecoveryEngine
must never call borrow() or reset() from more than one
thread concurrently. No locking is provided; concurrent use is undefined.
TGSqlParser.prepareForReuse() (available since GSP 3.2.0.0)
clears cached vendor parser, the SQL environment, the source filename, the
statement list, and the syntax-error list, and resets parsing options to
their defaults. The pool's reset() method invokes
prepareForReuse() and additionally calls
setSqltext("") which atomically
clears sqltext, sqlfilename, and the cached
sqlInputStream. prepareForReuse as of 3.2.x does not
touch sqlInputStream, so this extra step is required to avoid a
prior file-based parse's stream leaking into the next call.
Note: setSqlInputStream(null) would throw because of an
unconditional new BufferedInputStream(input) on its else branch.
The setSqltext("") path is the only safe way to null out the
stream field from public API.
Reset is idempotent and safe to call before the first borrow().
Plan reference: §5.3, §7.3/S12, §7.4/S12, §13/R1.
| Constructor and Description |
|---|
ParserPool(EDbVendor vendor) |
| Modifier and Type | Method and Description |
|---|---|
TGSqlParser |
borrow()
Return the pooled parser, allocating it on the first call.
|
long |
getBorrowCount()
Number of times
borrow() has been called. |
long |
getResetCount()
Number of times
reset() has been called. |
EDbVendor |
getVendor() |
boolean |
isAllocated()
True when the pool has allocated its parser.
|
void |
reset()
Clear stale parser state so the next
borrow() sees a clean
baseline. |
public ParserPool(EDbVendor vendor)
public TGSqlParser borrow()
getBorrowCount().public void reset()
borrow() sees a clean
baseline. Safe to call before the first borrow (no-op). Increments
getResetCount() regardless.
prepareForReuse() (performance)TGSqlParser.prepareForReuse() nulls the cached
vendor parser. The vendor parser owns the YACC/LEX parse tables —
large int[]/long[] arrays (~100KB+ per dialect). Nulling
it forces parse() to re-create the vendor parser and reload those
tables on every region. On a script with hundreds of statement
regions that is hundreds of full table reloads — measured at ~351MB of
int[] churn for an 18KB / 534-region invalid script, which pushes
the formatter into GC thrash (and OOM-to-FAILED) under a constrained heap
(-Xmx512m). getVendorParser() is explicitly designed to cache and
reuse the vendor parser across parse() calls, so reusing it
between regions is the supported path, not a hack. (Root-caused in S36;
gates S37. plan §13/R14, R16.)
A lighter reset is sufficient because doparse() already
rebuilds sourcetokenlist and sqlstatements and clears
syntaxErrors at the start of every parse. We only need to clear
the input fields here: setSqltext("") atomically clears
sqltext, sqlfilename, AND the cached sqlInputStream
(calling setSqlInputStream(null) would throw, so setSqltext
is the only safe way to null the stream field from public API).
public long getBorrowCount()
borrow() has been called.public long getResetCount()
reset() has been called.public boolean isAllocated()