All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.quasardb.qdb.ts.Writer Maven / Gradle / Ivy

Go to download

API for the JNI components of the QuasarDB API for Java. Should not be included directly.

There is a newer version: 3.14.1
Show newest version
package net.quasardb.qdb.ts;

import java.io.IOException;
import java.io.Flushable;
import java.lang.AutoCloseable;
import java.sql.Timestamp;
import java.time.LocalDateTime;

import java.nio.channels.SeekableByteChannel;
import java.util.*;

import net.quasardb.qdb.*;
import net.quasardb.qdb.exception.ExceptionFactory;
import net.quasardb.qdb.exception.InvalidArgumentException;
import net.quasardb.qdb.jni.*;

/**
 * High-performance bulk writer for a QuasarDB timeseries table.
 *
 * Usage of instances of this class is not thread-safe. Use a Writer
 * instance per Thread in multi-threaded situations.
 */
public class Writer implements AutoCloseable, Flushable {
    boolean async;
    Session session;
    Long batchTable;
    List columns;

    /**
     * Maintains a cache of table offsets so we can easily look them up
     * later.
     */
    Map tableOffsets;

    /**
     * Helper class to represent a table and column pair, which we
     * need because we need to lay out all columns as flat array.
     */
    public static class TableColumn {
        public String table;
        public String column;

        public TableColumn(String table, String column) {
            this.table = table;
            this.column = column;
        }

        public String toString() {
            return "TableColumn (table: " + this.table + ", column: " + this.column + ")";
        }
    }

    protected Writer(Session session, Table[] tables) {
        this(session, tables, false);
    }

    protected Writer(Session session, Table[] tables, boolean async) {
        this.async = async;
        this.session = session;
        this.tableOffsets = new HashMap();
        this.columns = new ArrayList();

        for (Table table : tables) {
            this.tableOffsets.put(table.name, this.columns.size());

            for (Column column : table.columns) {
                this.columns.add(new TableColumn(table.name, column.name));
            }
        }

        TableColumn[] tableColumns = this.columns.toArray(new TableColumn[columns.size()]);
        Reference theBatchTable = new Reference();
        int err = qdb.ts_batch_table_init(this.session.handle(),
                                          tableColumns,
                                          theBatchTable);
        ExceptionFactory.throwIfError(err);

        this.batchTable = theBatchTable.value;
    }

    /**
     * After a writer is already initialized, this function allows extra tables to
     * be added to the internal state. Blocking function that needs to communicate with
     * the QuasarDB daemon to retrieve metadata.
     */
    public void extraTables(Table[] tables) {
        List columns = new ArrayList();

        for (Table table : tables) {
            this.tableOffsets.put(table.name, this.columns.size());

            for (Column column : table.columns) {
                this.columns.add(new TableColumn(table.name, column.name));
                columns.add(new TableColumn(table.name, column.name));
            }
        }

        TableColumn[] tableColumns = columns.toArray(new TableColumn[columns.size()]);
        int err = qdb.ts_batch_table_extra_columns(this.batchTable,
                                                   tableColumns);
        ExceptionFactory.throwIfError(err);

    }

    public void extraTables(Table table) {
        extraTables(new Table[] { table });
    }

    /**
     * Utility function that looks up a table's index with the batch being written
     * by its name. The first table starts with column 0, but depending upon the amount
     * of columns in other tables, it can influence the offset of the table within the batch.
     *
     * If possible, you are encouraged to cache this value so that recurring writes
     * of rows to the same table only do this lookup once.
     */
    public int tableIndexByName(String name) {
        Integer offset = this.tableOffsets.get(name);
        if (offset == null) {
            throw new InvalidArgumentException();
        }

        return offset.intValue();
    }

    /**
     * Cleans up the internal representation of the batch table.
     */
    @Override
    protected void finalize() throws Throwable {
        try {
            qdb.ts_batch_table_release(this.session.handle(), this.batchTable);
        } finally {
            super.finalize();
        }
    }

    /**
     * Closes the timeseries table and local cache so that memory can be reclaimed. Flushes
     * all remaining output.
     */
    public void close() throws IOException {
        this.flush();
        qdb.ts_batch_table_release(this.session.handle(), this.batchTable);

        this.batchTable = null;
    }

    /**
     * Flush current local cache to server.
     */
    public void flush() throws IOException {
        int err;
        if (this.async == true) {
            err = qdb.ts_batch_push_async(this.batchTable);
        } else {
            err = qdb.ts_batch_push(this.batchTable);
        }
        ExceptionFactory.throwIfError(err);
    }

    /**
     * Append a new row to the local table cache. Should be periodically flushed,
     * unless an {@link AutoFlushWriter} is used.
     *
     * @param offset Relative offset of the table inside the batch. Use #tableIndexByName
     *               to determine the appropriate value.
     * @param timestamp Timestamp of the row
     * @param values Values being inserted, mapped to columns by their relative offset.
     *
     * @see #tableIndexByName
     * @see #flush
     * @see Table#autoFlushWriter
     */
    public void append(Integer offset, Timespec timestamp, Value[] values) throws IOException {
        int err = qdb.ts_batch_table_row_append(this.batchTable, offset, timestamp, values);
        ExceptionFactory.throwIfError(err);
    }

    /**
     * Append a new row to the local table cache. Should be periodically flushed,
     * unless an {@link AutoFlushWriter} is used.
     *
     * This function automatically looks up a table's offset by its name. For performance
     * reason, you are encouraged to manually invoke and cache the value of #tableIndexByName
     * whenever possible.
     *
     * @param tableName Name of the table to insert to.
     * @param timestamp Timestamp of the row
     * @param values Values being inserted, mapped to columns by their relative offset.
     *
     * @see #tableIndexByName
     * @see #flush
     * @see Table#autoFlushWriter
     */
    public void append(String tableName, Timespec timestamp, Value[] values) throws IOException {
        this.append(this.tableIndexByName(tableName),
                    timestamp,
                    values);
    }


    /**
     * Append a new row to the local table cache. Should be periodically flushed,
     * unless an {@link AutoFlushWriter} is used.
     *
     * This is a convenience function that assumes only one table is being inserted
     * to and should not be used when inserts to multiple tables are being batched.
     *
     * @param timestamp Timestamp of the row
     * @param values Values being inserted, mapped to columns by their relative offset.
     *
     * @see #tableIndexByName
     * @see #flush
     * @see Table#autoFlushWriter
     */
    public void append(Timespec timestamp, Value[] values) throws IOException {
        this.append(0, timestamp, values);
    }

    /**
     * Append a new row to the local table cache. Should be periodically flushed,
     * unless an {@link AutoFlushWriter} is used.
     *
     * @param offset Relative offset of the table inside the batch. Use #tableIndexByName
     *               to determine the appropriate value.
     * @param row Row being inserted.
     *
     * @see #tableIndexByName
     * @see #flush
     * @see Table#autoFlushWriter
     */
    public void append(Integer offset, Row row) throws IOException {
        this.append(offset,
                    row.getTimestamp(),
                    row.getValues());
    }

    /**
     * Append a new row to the local table cache. Should be periodically flushed,
     * unless an {@link AutoFlushWriter} is used.
     *
     * This function automatically looks up a table's offset by its name. For performance
     * reason, you are encouraged to manually invoke and cache the value of #tableIndexByName
     * whenever possible.
     *
     * @param tableName Name of the table to insert to.
     * @param row Row being inserted.
     *
     * @see #tableIndexByName
     * @see #flush
     * @see Table#autoFlushWriter
     */
    public void append(String tableName, Row row) throws IOException {
        this.append(this.tableIndexByName(tableName), row);
    }

    /**
     * Append a new row to the local table cache. Should be periodically flushed,
     * unless an {@link AutoFlushWriter} is used.
     *
     * This is a convenience function that assumes only one table is being inserted
     * to and should not be used when inserts to multiple tables are being batched.
     *
     * @param row Row being inserted.
     *
     * @see #tableIndexByName
     * @see #flush
     * @see Table#autoFlushWriter
     */
    public void append(Row row) throws IOException {
        this.append(0, row);
    }


    /**
     * Append a new row to the local table cache. Should be periodically flushed,
     * unless an {@link AutoFlushWriter} is used.
     *
     * @param offset Relative offset of the table inside the batch. Use #tableIndexByName
     *               to determine the appropriate value.
     * @param timestamp Timestamp of the row
     * @param values Values being inserted, mapped to columns by their relative offset.
     *
     * @see #tableIndexByName
     * @see #flush
     * @see Table#autoFlushWriter
     */
    public void append(Integer offset, LocalDateTime timestamp, Value[] values) throws IOException {
        this.append(offset, new Timespec(timestamp), values);
    }

    /**
     * Append a new row to the local table cache. Should be periodically flushed,
     * unless an {@link AutoFlushWriter} is used.
     *
     * This function automatically looks up a table's offset by its name. For performance
     * reason, you are encouraged to manually invoke and cache the value of #tableIndexByName
     * whenever possible.
     *
     * @param tableName Name of the table to insert to.
     * @param timestamp Timestamp of the row
     * @param values Values being inserted, mapped to columns by their relative offset.
     *
     * @see #tableIndexByName
     * @see #flush
     * @see Table#autoFlushWriter
     */
    public void append(String tableName, LocalDateTime timestamp, Value[] values) throws IOException {
        this.append(this.tableIndexByName(tableName), timestamp, values);
    }


    /**
     * Append a new row to the local table cache. Should be periodically flushed,
     * unless an {@link AutoFlushWriter} is used.
     *
     * This is a convenience function that assumes only one table is being inserted
     * to and should not be used when inserts to multiple tables are being batched.
     *
     * @param timestamp Timestamp of the row
     * @param values Values being inserted, mapped to columns by their relative offset.
     *
     * @see #tableIndexByName
     * @see #flush
     * @see Table#autoFlushWriter
     */
    public void append(LocalDateTime timestamp, Value[] values) throws IOException {
        this.append(0, timestamp, values);
    }

    /**
     * Append a new row to the local table cache. Should be periodically flushed,
     * unless an {@link AutoFlushWriter} is used.
     *
     * @param offset Relative offset of the table inside the batch. Use #tableIndexByName
     *               to determine the appropriate value.
     * @param timestamp Timestamp of the row
     * @param values Values being inserted, mapped to columns by their relative offset.
     *
     * @see #tableIndexByName
     * @see #flush
     * @see Table#autoFlushWriter
     */
    public void append(Integer offset, Timestamp timestamp, Value[] values) throws IOException {
        this.append(offset, new Timespec(timestamp), values);
    }

    /**
     * Append a new row to the local table cache. Should be periodically flushed,
     * unless an {@link AutoFlushWriter} is used.
     *
     * This function automatically looks up a table's offset by its name. For performance
     * reason, you are encouraged to manually invoke and cache the value of #tableIndexByName
     * whenever possible.
     *
     * @param tableName Name of the table to insert to.
     * @param timestamp Timestamp of the row
     * @param values Values being inserted, mapped to columns by their relative offset.
     *
     * @see #tableIndexByName
     * @see #flush
     * @see Table#autoFlushWriter
     */
    public void append(String tableName, Timestamp timestamp, Value[] values) throws IOException {
        this.append(this.tableIndexByName(tableName), timestamp, values);
    }

    /**
     * Append a new row to the local table cache. Should be periodically flushed,
     * unless an {@link AutoFlushWriter} is used.
     *
     * This is a convenience function that assumes only one table is being inserted
     * to and should not be used when inserts to multiple tables are being batched.
     *
     * @param timestamp Timestamp of the row
     * @param values Values being inserted, mapped to columns by their relative offset.
     *
     * @see #tableIndexByName
     * @see #flush
     * @see Table#autoFlushWriter
     */
    public void append(Timestamp timestamp, Value[] values) throws IOException {
        this.append(0, timestamp, values);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy