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

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

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

import io.github.shanqiang.exception.OutOfOrderException;
import org.apache.arrow.util.VisibleForTesting;

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

import static io.github.shanqiang.table.Table.createEmptyTableLike;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;

public class SlideTableOffheap implements SlideTable {
    private Table table;
    private final String timeColumnName;
    private final int timeColumnIndex;
    private int start;
    private int size;

    public SlideTableOffheap(Table table, String timeColumnName) {
        this.timeColumnName = requireNonNull(timeColumnName);
        this.timeColumnIndex = table.getIndex(timeColumnName);
    }

    @Override
    public void addRow(Table table, int row) {
        long ts = (long) table.getColumn(timeColumnIndex).get(row);
        if (size > 0) {
            long pre = (long) this.table.getColumn(timeColumnIndex).get(start + size - 1);
            if (ts < pre) {
                throw new OutOfOrderException(format("ts: %d, pre: %d", ts, pre));
            }
        }

        if (null == this.table) {
            //懒加载。需要的时候才创建表
            this.table = createEmptyTableLike(table);
        }
        this.table.append(table, row);

        size++;
    }

    @Override
    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;
        }
        Column column = table.getColumn(timeColumnIndex);
        int left = start;
        int right = start + size;
        int mid;
        long v;
        while (true) {
            if (right == left + 1) {
                v = (long) column.get(left);
                if (ts > v) {
                    return right;
                }
                return -1;
            }
            mid = (left + right) / 2;
            v = (long) column.get(mid);
            if (ts <= v) {
                right = mid;
            } else {
                left = mid;
            }
        }
    }

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

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

    @Override
    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) {
                //懒加载。后面需要的时候再创建表,size==0之后SortedTableByTime被整个释放掉的概率很大
                this.table = null;
            } else if (size > 0) {
                Table table = createEmptyTableLike(this.table);
                for (int i = start; i < start + size; i++) {
                    table.append(this.table, i);
                }
                this.table = table;
            } else {
                throw new IllegalStateException(format("size: %d", size));
            }
            start = 0;
        }
    }

    @Override
    public int size() {
        return size;
    }

    @VisibleForTesting
    public int tableSize() {
        return table.size();
    }

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

        return rows;
    }

    @Override
    public long firstTime() {
        return (long) table.getColumn(timeColumnIndex).get(start);
    }

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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy