Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 650de3dc authored by Jeff Brown's avatar Jeff Brown
Browse files

Optimize fillWindow to improve reverse-seek performance.

Bug: 5520301

When an application requests a row from a SQLiteCursor that
is not in the window, instead of filling from the requested
row position onwards, fill from a little bit ahead of the
requested row position.

This fixes a problem with applications that seek backwards
in large cursor windows.  Previously the application could
end up refilling the window every time it moved back
one position.

We try to fill about 1/3 before the requested position and
2/3 after which substantially improves scrolling responsiveness
when the list is bound to a data set that does not fit
entirely within one cursor window.

Change-Id: I168ff1d3aed1a41ac96267be34a026c108590e52
parent 4257e3b1
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -180,13 +180,13 @@ final class BulkCursorProxy implements IBulkCursor {
        return mRemote;
    }

    public CursorWindow getWindow(int startPos) throws RemoteException
    public CursorWindow getWindow(int position) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            data.writeInterfaceToken(IBulkCursor.descriptor);
            data.writeInt(startPos);
            data.writeInt(position);

            mRemote.transact(GET_CURSOR_WINDOW_TRANSACTION, data, reply, 0);
            DatabaseUtils.readExceptionFromParcel(reply);
+5 −6
Original line number Diff line number Diff line
@@ -132,11 +132,11 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
    }

    @Override
    public CursorWindow getWindow(int startPos) {
    public CursorWindow getWindow(int position) {
        synchronized (mLock) {
            throwIfCursorIsClosed();

            if (!mCursor.moveToPosition(startPos)) {
            if (!mCursor.moveToPosition(position)) {
                closeFilledWindowLocked();
                return null;
            }
@@ -149,12 +149,11 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
                if (window == null) {
                    mFilledWindow = new CursorWindow(mProviderName);
                    window = mFilledWindow;
                    mCursor.fillWindow(startPos, window);
                } else if (startPos < window.getStartPosition()
                        || startPos >= window.getStartPosition() + window.getNumRows()) {
                } else if (position < window.getStartPosition()
                        || position >= window.getStartPosition() + window.getNumRows()) {
                    window.clear();
                    mCursor.fillWindow(startPos, window);
                }
                mCursor.fillWindow(position, window);
            }

            // Acquire a reference before returning from this RPC.
+18 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
    public int mWindowPtr;

    private int mStartPos;
    private final String mName;

    private final CloseGuard mCloseGuard = CloseGuard.get();

@@ -84,6 +85,8 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
    private static native boolean nativePutDouble(int windowPtr, double value, int row, int column);
    private static native boolean nativePutNull(int windowPtr, int row, int column);

    private static native String nativeGetName(int windowPtr);

    /**
     * Creates a new empty cursor window and gives it a name.
     * <p>
@@ -95,6 +98,7 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
     */
    public CursorWindow(String name) {
        mStartPos = 0;
        mName = name;
        mWindowPtr = nativeCreate(name, sCursorWindowSize);
        if (mWindowPtr == 0) {
            throw new CursorWindowAllocationException("Cursor window allocation of " +
@@ -129,6 +133,7 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
            throw new CursorWindowAllocationException("Cursor window could not be "
                    + "created from binder.");
        }
        mName = nativeGetName(mWindowPtr);
        mCloseGuard.open("close");
    }

@@ -155,6 +160,14 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
        }
    }

    /**
     * Gets the name of this cursor window.
     * @hide
     */
    public String getName() {
        return mName;
    }

    /**
     * Closes the cursor window and frees its underlying resources when all other
     * remaining references have been released.
@@ -758,4 +771,9 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
        String s = (buff.length() > 980) ? buff.substring(0, 980) : buff.toString();
        return "# Open Cursors=" + total + s;
    }

    @Override
    public String toString() {
        return getName() + " {" + Integer.toHexString(mWindowPtr) + "}";
    }
}
+26 −0
Original line number Diff line number Diff line
@@ -725,6 +725,32 @@ public class DatabaseUtils {
        }
    }

    /**
     * Picks a start position for {@link Cursor#fillWindow} such that the
     * window will contain the requested row and a useful range of rows
     * around it.
     *
     * When the data set is too large to fit in a cursor window, seeking the
     * cursor can become a very expensive operation since we have to run the
     * query again when we move outside the bounds of the current window.
     *
     * We try to choose a start position for the cursor window such that
     * 1/3 of the window's capacity is used to hold rows before the requested
     * position and 2/3 of the window's capacity is used to hold rows after the
     * requested position.
     *
     * @param cursorPosition The row index of the row we want to get.
     * @param cursorWindowCapacity The estimated number of rows that can fit in
     * a cursor window, or 0 if unknown.
     * @return The recommended start position, always less than or equal to
     * the requested row.
     * @hide
     */
    public static int cursorPickFillWindowStartPosition(
            int cursorPosition, int cursorWindowCapacity) {
        return Math.max(cursorPosition - cursorWindowCapacity / 3, 0);
    }

    /**
     * Query the table for the number of rows in the table.
     * @param db the database the table is in
+9 −3
Original line number Diff line number Diff line
@@ -30,11 +30,17 @@ import android.os.RemoteException;
 */
public interface IBulkCursor extends IInterface  {
    /**
     * Returns a BulkCursorWindow, which either has a reference to a shared
     * memory segment with the rows, or an array of JSON strings.
     * Gets a cursor window that contains the specified position.
     * The window will contain a range of rows around the specified position.
     */
    public CursorWindow getWindow(int startPos) throws RemoteException;
    public CursorWindow getWindow(int position) throws RemoteException;

    /**
     * Notifies the cursor that the position has changed.
     * Only called when {@link #getWantsAllOnMoveCalls()} returns true.
     *
     * @param position The new position
     */
    public void onMove(int position) throws RemoteException;

    /**
Loading