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

io.github.shanqiang.table.SlideTableByColumn Maven / Gradle / Ivy

The newest version!
package io.github.shanqiang.table;

import io.github.shanqiang.exception.OutOfOrderException;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import static java.lang.String.format;

public class SlideTableByColumn implements SlideTable {
    private List> table;
    private final LinkedHashMap columnName2Index = new LinkedHashMap<>();
    private final int timeColumnIndex;
    private int start;
    private int size;

    public SlideTableByColumn(Table table, String timeColumnName) {
        int columnSize = table.getColumns().size();
        for (int i = 0; i < columnSize; i++) {
            columnName2Index.put(table.getColumn(i).name(), i);
        }
        timeColumnIndex = columnName2Index.get(timeColumnName);
    }

    private void initTable() {
        if (null == table) {
            int columnSize = columnName2Index.size();
            table = new ArrayList<>(columnSize);
            for (int i = 0; i < columnSize; i++) {
                table.add(new ArrayList<>());
            }
        }
    }

    public void addRow(Table table, int row) {
        long ts = (long) table.getColumn(timeColumnIndex).get(row);
        if (size > 0) {
            long pre = (long) this.table.get(timeColumnIndex).get(start + size - 1);
            if (ts < pre) {
                throw new OutOfOrderException(format("ts: %d, pre: %d, check the ts column value or use greater watermark", ts, pre));
            }
        }

        initTable();

        for (int i = 0; i < this.table.size(); i++) {
            this.table.get(i).add(table.getColumn(i).get(row));
        }

        size++;
    }

    public int countLessThan(long ts) {
        int loc = locate(ts);
        if (-1 == loc) {
            return 0;
        }

        return loc - this.start;
    }

    /**
     * 对于0,1,2,3,5,6,8 执行locate(0)为-1,locate(4)的结果为4,locate(7)的结果为6
     * @param ts
     * @return
     */
    private int locate(long ts) {
        if (size < 1) {
            return -1;
        }

        int left = start;
        int right = start + size;
        int mid;
        long v;
        while (true) {
            if (right == left + 1) {
                v = (long) table.get(timeColumnIndex).get(left);
                if (ts > v) {
                    return right;
                }
                return -1;
            }
            mid = (left + right) / 2;
            v = (long) table.get(timeColumnIndex).get(mid);
            if (ts <= v) {
                right = mid;
            } else {
                left = mid;
            }
        }
    }

    public void removeLessThan(long ts) {
        int loc = locate(ts);
        if (-1 == loc) {
            return;
        }

        size -= loc - start;
        start = loc;
        realRemove();
    }

    public void removeFirstRow() {
        if (size < 1) {
            throw new IllegalStateException("no row");
        }
        start++;
        size--;

        realRemove();
    }

    private void realRemove() {
        if (table.size() < 2) {
            return;
        }

        //删掉的行数超过一半才进行一次重新整理以提升性能,最多浪费一倍内存
        //最坏情况为大量的3条删两条的case这种情况下性能最差但如果增加一个比如超过1000条并且超过一半才删的条件的话可能会造成1000倍的内存浪费以至crash
        if (start > this.table.size() / 2) {
            if (0 == size) {
                this.table = null;
            } else if (size > 0) {
                List> table = new ArrayList<>(columnName2Index.size());
                for (int j = 0; j < columnName2Index.size(); j++) {
                    List column = new ArrayList<>(size);
                    for (int i = start; i < start + size; i++) {
                        column.add(this.table.get(j).get(i));
                    }
                    table.add(column);
                }
                this.table = table;
            } else {
                throw new IllegalStateException(format("size: %d", size));
            }
            start = 0;
        }
    }

    public int size() {
        return size;
    }

    public List rows() {
        List rows = new ArrayList<>(size);
        for (int i = start; i < start + size; i++) {
            rows.add(new RowByTableHeap(columnName2Index, table, i));
        }

        return rows;
    }

    public long firstTime() {
        return (long) this.table.get(timeColumnIndex).get(start);
    }

    public long lastTime() {
        return (long) this.table.get(timeColumnIndex).get(start + size - 1);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy