Package com.persistit.ui

Source Code of com.persistit.ui.ManagementSlidingTableModel$Fetcher

/**
* Copyright © 2005-2012 Akiban Technologies, Inc.  All rights reserved.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* This program may also be available under different license terms.
* For more information, see www.akiban.com or contact licensing@akiban.com.
*
* Contributors:
* Akiban Technologies, Inc.
*/

package com.persistit.ui;

import java.rmi.RemoteException;

import javax.swing.SwingUtilities;

import com.persistit.Key;
import com.persistit.KeyState;
import com.persistit.Management;
import com.persistit.Management.LogicalRecordCount;

/**
* @version 1.0
*/
class ManagementSlidingTableModel extends ManagementTableModel {
    public final static int DEFAULT_ROW_CACHE_SIZE = 2048;
    public final static int DEFAULT_INITIAL_SIZE_ESTIMATE = 10000;
    public final static int SCROLL_BAR_ESTIMATE_MULTIPLIER = 3;
    public final static int MAXIMUM_GROWTH_ESTIMATE = 100000;
    public final static int DEFAULT_MAXIMUM_VALUE_SIZE = 400;
    public final static int MINIMUM_REQUESTED_ROW_COUNT = 256;

    /**
     * Offset from beginning of logical keyspace to the first row in the row
     * cache.
     */
    private int _offset;
    private boolean _deletingRows;

    /**
     * Size of _infoArray row cache
     */
    private final int _rowCacheSize = DEFAULT_ROW_CACHE_SIZE;

    private final int _maxValueSize = DEFAULT_MAXIMUM_VALUE_SIZE;
    /**
     * Current estimate of total row count
     */
    private int _currentRowCount;
    /**
     * Indicates whether the total size is definite, meaning that we have
     * traversed to the end of the logical key space and discovered the actual
     * count.
     */
    private boolean _definite;
    /**
     * Count of valid rows in the row cache.
     */
    private int _valid = 0;

    /**
     * The volume name
     */
    private String _volumeName;
    /**
     * The tree name
     */
    private String _treeName;
    /**
     * The KeyFilter, represented as a string. If null, then all keys in the
     * tree are selected.
     */
    private String _keyFilterString;

    /**
     * Indicates that the row cache is unstable because a fetch operation is
     * currently pending.
     */
    private boolean _waiting;

    /**
     * Construct a TableModel to display one of the management info array
     * structures such as BufferInfo[]. Each column is described by a property
     * defined in the <code>ResourceBundle</code> associated with this class.
     * The property name is constructed from the last "." piece of the name of
     * the supplied class and the column index as follows: <code><pre>
     * property Name ::=
     *      <i>classNameTail</i>.column.<i>columnIndex</i>
     * </pre></code> For example, the specification for the first column of the
     * {@link com.persistit.Management.BufferInfo} class is <code><pre>
     *      BufferInfo.column.0
     * </pre></code> The value associated with this property has the following
     * structure: <code><pre>
     * property Value ::=
     *      <i>accessorMethodName</i>:<i>width</i>:<i>flags</i>:<i>header</i>
     * </code></pre> For example <code><pre>
     *      getRightSiblingAddress:10:A:Right Pointer
     * </code></pre> where the <i>accessorMethodName</code> is simply a method
     * name in the supplied class (the method must take no arguments), the
     * <i>width</i> is a percentage of the total table width, and
     * <i>justification</i> is L, C or R.
     *
     * @param clazz
     */

    public ManagementSlidingTableModel(final Class clazz, final String className, final AdminUI ui)
            throws NoSuchMethodException {
        super(clazz, className, ui);
    }

    void reset() {
        _volumeName = null;
        _treeName = null;
        _keyFilterString = null;
        _valid = 0;
        _offset = 0;
        _currentRowCount = DEFAULT_INITIAL_SIZE_ESTIMATE;
        _definite = false;
    }

    void set(final String volumeName, final String treeName, final String keyFilterString) {
        reset();
        _volumeName = volumeName;
        _treeName = treeName;
        _keyFilterString = keyFilterString;
        fireTableDataChanged();
    }

    boolean isDeletingRows() {
        return _deletingRows;
    }

    @Override
    public int getRowCount() {
        return _currentRowCount;
    }

    @Override
    public Object getValueAt(final int row, final int col) {
        // if ((row % 1000) == 0 && col == 0) System.out.println("Getting row "
        // + row);
        if (row < 0 || (_definite && row >= _currentRowCount)) {
            return null;
        } else if (col >= 0 && (row < _offset || row >= _offset + _valid)) {
            return fetch(row);
        } else {
            return super.getValueAt(row - _offset, col);
        }
    }

    private synchronized Object fetch(final int row) {
        if (_waiting) {
            return _adminUI.getWaitingMessage();
        }
        _waiting = true;

        int fromOffset;
        int requestedCount;
        int skipCount = 0;
        boolean forward;

        if (_valid == 0) {
            forward = true;
            fromOffset = -1;
            requestedCount = row + 1;
        } else if (row >= _offset + _valid) {
            forward = true;
            fromOffset = _offset + _valid - 1;
            requestedCount = row - (_offset + _valid) + 1;
        } else if (row < _offset && row > _offset - row) {
            forward = false;
            requestedCount = _offset - row;
            fromOffset = _offset;
        } else {
            forward = true;
            fromOffset = -1;
            requestedCount = row + 1;
        }

        if (requestedCount < MINIMUM_REQUESTED_ROW_COUNT) {
            requestedCount = MINIMUM_REQUESTED_ROW_COUNT;
        } else {
            if (requestedCount > _rowCacheSize) {
                skipCount = requestedCount - (_rowCacheSize / 2);
                requestedCount = _rowCacheSize;
            }
        }

        // System.out.println(
        // "new Fetcher(forward=" + forward +
        // ",fromOffset=" + fromOffset + ",requestedCount=" + requestedCount +
        // ",skipCount=" + skipCount + "): _offset=" + _offset +
        // " and _valid=" + _valid);
        final Fetcher fetcher = new Fetcher(forward, fromOffset, requestedCount, skipCount);
        new Thread(fetcher).start();
        return _adminUI.getWaitingMessage();
    }

    private synchronized void receiveData(final Fetcher fetcher) {
        _waiting = false;
        if (fetcher._exception != null) {
            _adminUI.postException(fetcher._exception);
        }
        if (fetcher._resultRows == null)
            return;

        if (_infoArray == null || _infoArray.length != _rowCacheSize) {
            _infoArray = new Object[_rowCacheSize];
            _offset = 0;
            _valid = 0;
        }

        final int count = fetcher._resultRows.length;
        int newValid = _valid + count;

        // System.out.println(
        // "receivedData(_offset=" + _offset +
        // ",_valid=" + _valid +
        // ",count=" + count +
        // ",fetcher._from=" + fetcher._from +
        // ",fetcher._forward=" + fetcher._forward +
        // ",fetcher._skipCount=" + fetcher._skipCount +
        // ",fetcher._requestedCount=" + fetcher._requestedCount
        // );

        final int oldOffset = _offset;
        int newOffset = oldOffset;
        final int oldRowCount = _currentRowCount;
        int firstUpdatedRow;
        int lastUpdatedRow;

        int lost = 0; // rows lost from row cache
        int kept = _valid; // rows kept from row cache
        int cut = 0; // rows cut from fetcher._resultRows

        if (fetcher._forward) {
            if (fetcher._from != _offset + _valid - 1) {
                _valid = 0;
                kept = 0;
                newValid = count;
                newOffset = fetcher._from + 1;
            }
            if (newValid > _rowCacheSize) {
                lost = newValid - _rowCacheSize;
                newOffset += lost;

                if (lost < _valid) {
                    kept = _valid - lost;
                    System.arraycopy(_infoArray, lost, _infoArray, 0, kept);
                } else {
                    cut = lost - _valid;
                    kept = 0;
                }
                newValid = _rowCacheSize;
            }
            System.arraycopy(fetcher._resultRows, cut, _infoArray, kept, count - cut);

            firstUpdatedRow = newOffset + kept;
            lastUpdatedRow = firstUpdatedRow + count - cut - 1;

            if (count < fetcher._requestedCount) {
                changeRowCount(newOffset + newValid, true);
            }
        } else {
            if (fetcher._from != _offset) {
                _valid = 0;
                kept = 0;
                newValid = count;
                newOffset = fetcher._from - count;
            } else {
                newOffset = oldOffset - count;
            }
            if (newValid > _rowCacheSize) {
                lost = newValid - _rowCacheSize;
                if (lost < _valid) {
                    kept = _valid - lost;
                    System.arraycopy(_infoArray, 0, _infoArray, _valid - kept, kept);
                } else {
                    cut = lost - _valid;
                    kept = 0;
                }
                newValid = _rowCacheSize;
            }
            System.arraycopy(fetcher._resultRows, 0, _infoArray, 0, count - cut);

            firstUpdatedRow = newOffset;
            lastUpdatedRow = firstUpdatedRow + count - cut - 1;

            if (count < fetcher._requestedCount) {
                _definite = false;
                _currentRowCount = DEFAULT_INITIAL_SIZE_ESTIMATE;
                _offset = 0;
            }
        }
        _offset = newOffset;
        _valid = newValid;

        if (!_definite) {
            final int receivedRowCount = newOffset + newValid;
            int estimatedRowCount = (newOffset + _valid) * SCROLL_BAR_ESTIMATE_MULTIPLIER;
            if (estimatedRowCount - receivedRowCount > MAXIMUM_GROWTH_ESTIMATE) {
                estimatedRowCount = receivedRowCount + MAXIMUM_GROWTH_ESTIMATE;
            }

            if (_currentRowCount < estimatedRowCount && _offset + _valid > _currentRowCount) {
                changeRowCount(estimatedRowCount, false);
            }
        }
        fireTableRowsUpdated(0, _currentRowCount - 1);
    }

    private void changeRowCount(final int newRowCount, final boolean definite) {
        // System.out.println(
        // "Changing row count from " + _currentRowCount +
        // " to " + newRowCount +
        // " definite=" + definite);

        _deletingRows = true;

        final int oldRowCount = _currentRowCount;
        _definite = definite;
        _currentRowCount = newRowCount;

        if (oldRowCount < newRowCount) {
            // System.out.println("fireTableRowsInserted(" + oldRowCount + "," +
            // (newRowCount - 1) + ")");
            fireTableRowsInserted(oldRowCount, newRowCount - 1);
        } else if (oldRowCount > newRowCount) {
            // System.out.println("fireTableRowsDeleted(" + newRowCount + "," +
            // (oldRowCount - 1) + ")");
            fireTableRowsDeleted(newRowCount, oldRowCount - 1);
        }

        _deletingRows = false;
    }

    private class Fetcher implements Runnable {
        boolean _forward;
        int _from;
        int _requestedCount;
        int _skipCount;

        Object[] _resultRows;
        Exception _exception;

        Fetcher(final boolean forward, final int from, final int requestedCount, final int skipCount) {
            _forward = forward;
            _from = from;
            _requestedCount = requestedCount;
            _skipCount = skipCount;
        }

        @Override
        public void run() {
            Management.LogicalRecord rec = null;
            if (_from != -1) {
                rec = (Management.LogicalRecord) _infoArray[_from - _offset];
            }
            KeyState ks = rec == null ? KeyState.LEFT_GUARD_KEYSTATE : rec.getKeyState();
            final Management management = _adminUI.getManagement();
            _resultRows = new Management.LogicalRecord[0];
            if (management != null) {
                try {
                    if (_skipCount > 0) {
                        final LogicalRecordCount lrc = management.getLogicalRecordCount(_volumeName, _treeName,
                                _keyFilterString, ks, _forward ? Key.GT : Key.LT, _skipCount);
                        final int skipped = lrc.getCount();
                        if (skipped > 0) {
                            ks = lrc.getKeyState();
                            _from = _forward ? _from + skipped : _from - skipped;
                        }
                    }

                    _resultRows = management.getLogicalRecordArray(_volumeName, _treeName, _keyFilterString, ks,
                            _forward ? Key.GT : Key.LT, _requestedCount, _maxValueSize, true);
                } catch (final RemoteException remoteException) {
                    // TODO
                    _exception = remoteException;
                }
            }
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    receiveData(Fetcher.this);
                }
            });
        }
    }

}
TOP

Related Classes of com.persistit.ui.ManagementSlidingTableModel$Fetcher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.