diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/util/FunctionGeneratedTableFactory.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/util/FunctionGeneratedTableFactory.java index e11ff0d5a6e..867d600e0cc 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/util/FunctionGeneratedTableFactory.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/util/FunctionGeneratedTableFactory.java @@ -53,14 +53,17 @@ public static Table create(Supplier tableGenerator, int refreshIntervalMs } /** - * Create a table that refreshes based on the value of your function, automatically called when any of the - * {@code sourceTables} tick.
- * Note that the {@code tableGenerator} may access data in the {@code sourceTables} but should not perform further - * table operations on them -- since the operations may be memoized, it is possible that a table operation will - * return a table created by a previous invocation of the {@code tableGenerator}. Since that result will not have - * been included in the {@code sourceTables}, it is not guaranteed to have been processed by the - * {@code UpdateGraphProcessor}, allowing the {@code tableGenerator} to unexpectedly run against the memoized, - * not-yet-updated table. + * Create a table that refreshes based on the value of your function, automatically called in a + * dependency-respecting way when at least one of the {@code sourceTables} tick. + *

+ * Note that the {@code tableGenerator} may access data in the {@code sourceTables} but should not perform + * further table operations on them without careful handling. Table operations may be memoized, and it is possible + * that a table operation will return a table created by a previous invocation of the same operation. Since that + * result will not have been included in the {@code sourceTables}, it's not automatically treated as a dependency + * for purposes of determining when it's safe to invoke {@code tableGenerator}, allowing races to exist between + * accessing the operation result and that result's own update processing. It's best to include all dependencies + * directly in {@code sourceTables}, or only compute on-demand inputs under a + * {@link io.deephaven.engine.liveness.LivenessScope}. * * @param tableGenerator a function returning a table to copy into the output table * @param sourceTables The query engine does not know the details of your function inputs. If you are dependent on a diff --git a/py/server/deephaven/table_factory.py b/py/server/deephaven/table_factory.py index 6c0ba99e46a..5a695957854 100644 --- a/py/server/deephaven/table_factory.py +++ b/py/server/deephaven/table_factory.py @@ -358,13 +358,13 @@ def function_generated_table(table_generator: Callable[[], Table], The table definition must not change between invocations of the 'table_generator' function, or an exception will be raised. - Note: any tables used by the 'table_generator' function *MUST* be specified in the 'source_tables'. This - ensures that the 'table_generator' is rerun only *after* any changes to the 'source_tables' have been processed. - Additionally, while the 'table_generator' may access data in the 'source_tables', it should not perform further table - operations on them -- since the operations may be memoized, it is possible that a table operation will return a - table created by a previous invocation of the 'table_generator'. Since that result will not have been included in - the 'source_tables', it is not guaranteed to have been processed by the UpdateGraphProcessor, allowing the - 'table_generator' to unexpectedly run against the memoized, not-yet-updated table. + Note that the 'table_generator' may access data in the sourceTables but should not perform further table operations + on them without careful handling. Table operations may be memoized, and it is possible that a table operation will + return a table created by a previous invocation of the same operation. Since that result will not have been included + in the 'source_table', it's not automatically treated as a dependency for purposes of determining when it's safe to + invoke 'table_generator', allowing races to exist between accessing the operation result and that result's own update + processing. It's best to include all dependencies directly in 'source_table', or only compute on-demand inputs under + a LivenessScope. Args: table_generator (Callable[[], Table]): The table generator function. This function must return a Table.