1. #1
    Sencha User
    Join Date
    Nov 2010
    Posts
    90
    Vote Rating
    0
    atrubka is on a distinguished road

      0  

    Default Infinite loop when using LiveGridView with a small cache

    Infinite loop when using LiveGridView with a small cache


    I'm using october's version of GXT, so it's possible that it was addressed somehow.
    In case it's not yet fixed please see the testing code below. Make sure that number of rows visible is greater than 8, which is probably cacheSize (=10) * (1 - preloadFactor (=0.2)).

    The button flips the flag and reloads the loader. Once you press the button it starts loading rows indefinitely.

    Everything's in one file (imports are stripped).

    Code:
    public class TestComponent extends ContentPanel {
    	private final class FileListProxy extends
    			RpcProxy<BasePagingLoadResult<ModelData>> {
    		@Override
    		protected void load(Object loadConfig,
    				final AsyncCallback<BasePagingLoadResult<ModelData>> callback) {
    			if (_loadAllowed) {
    				PagingLoadConfig pagingLoadConfig = (PagingLoadConfig) loadConfig;
    				int offset = pagingLoadConfig.getOffset();
    				int limit = pagingLoadConfig.getLimit();
    
    				ArrayList<ModelData> mds = new ArrayList<ModelData>(offset
    						+ limit);
    				for (int i = offset; i < offset + limit; i++) {
    					BaseModelData md = new BaseModelData();
    					md.set("name",
    							"item_" + i + "_" + System.currentTimeMillis());
    					mds.add(md);
    				}
    				BasePagingLoadResult<ModelData> result = new BasePagingLoadResult<ModelData>(
    						mds, offset, 1000);
    				callback.onSuccess(result);
    			} else {
    				callback.onSuccess(new BasePagingLoadResult<ModelData>(
    						new ArrayList<ModelData>(0), 0, 0));
    			}
    		}
    	}
    
    	private static final class FileListDataReader implements
    			DataReader<PagingLoadResult<ModelData>> {
    		@Override
    		public PagingLoadResult<ModelData> read(Object loadConfig, Object data) {
    			return (BasePagingLoadResult<ModelData>) data;
    		}
    	}
    
    	private Grid<ModelData> _fileGrid;
    	private final FileListProxy _fileListProxy;
    	private final PagingLoader<PagingLoadResult<ModelData>> _fileListLoader;
    	private final ListStore<ModelData> _fileListStore;
    
    	private boolean _loadAllowed = false;
    
    	public TestComponent() {
    		super(new FillLayout());
    
    		_fileListProxy = new FileListProxy();
    		_fileListLoader = new BasePagingLoader<PagingLoadResult<ModelData>>(
    				_fileListProxy, new FileListDataReader());
    		_fileListLoader.setRemoteSort(true);
    		_fileListLoader.setSortDir(SortDir.DESC);
    		_fileListLoader.setSortField("name");
    		_fileListStore = new ListStore<ModelData>(_fileListLoader);
    	}
    
    	@Override
    	protected void onRender(Element parent, int index) {
    		super.onRender(parent, index);
    
    		setHeading("Live Grid Test");
    
    		List<ColumnConfig> columns = new ArrayList<ColumnConfig>();
    		ColumnConfig nameColumn = new ColumnConfig("name", "Name", 300);
    		columns.add(nameColumn);
    		ColumnModel cm = new ColumnModel(columns);
    
    		_fileGrid = new Grid<ModelData>(_fileListStore, cm);
    		_fileGrid.setLoadMask(true);
    
    		LiveGridView liveGridView = new LiveGridView();
    		liveGridView.setEmptyText("No records found");
    		liveGridView.setCacheSize(10);
    		_fileGrid.setView(liveGridView);
    
    		add(_fileGrid);
    
    		Button loadButton = new Button("Load/Unload",
    				new SelectionListener<ButtonEvent>() {
    					@Override
    					public void componentSelected(ButtonEvent ce) {
    						_loadAllowed = !_loadAllowed;
    						_fileListLoader.load();
    					}
    				});
    
    		LiveToolItem pageLabel = new LiveToolItem();
    		pageLabel.bindGrid(_fileGrid);
    
    		ToolBar bottomBar = new ToolBar();
    		bottomBar.add(loadButton);
    		bottomBar.add(new FillToolItem());
    		bottomBar.add(pageLabel);
    		add(bottomBar);
    	}
    }

  2. #2
    Sencha User
    Join Date
    Nov 2010
    Posts
    90
    Vote Rating
    0
    atrubka is on a distinguished road

      0  

    Default


    The cache size is not the only reason that causes infinite loop.
    Looks like it also depends on the scroller position within the cached segment.

  3. #3
    Sencha User
    Join Date
    Nov 2010
    Posts
    90
    Vote Rating
    0
    atrubka is on a distinguished road

      0  

    Default


    Please also note that we're using GXT 2.2.0.

  4. #4
    Sencha User
    Join Date
    Sep 2007
    Posts
    13,971
    Vote Rating
    132
    sven is a glorious beacon of light sven is a glorious beacon of light sven is a glorious beacon of light sven is a glorious beacon of light sven is a glorious beacon of light sven is a glorious beacon of light

      0  

    Default


    This should already be fixed in a later version. 2.2.0 is a very old release.

  5. #5
    Sencha User
    Join Date
    Nov 2010
    Posts
    90
    Vote Rating
    0
    atrubka is on a distinguished road

      0  

    Default


    We don't really want to upgrade to a later version as it may compromise stability of our system right before the deadline.
    I was wondering if it's possible to override a method or something with the updated code to fix the bug.

  6. #6
    Sencha User
    Join Date
    Nov 2010
    Posts
    90
    Vote Rating
    0
    atrubka is on a distinguished road

      0  

    Default


    Bumping the thread as we need to resolve it somehow ASAP.

  7. #7
    Sencha User
    Join Date
    Feb 2008
    Posts
    10
    Vote Rating
    0
    dali is on a distinguished road

      0  

    Default


    I can reproduce this bug by doing the following:
    1. Returning a result of 0 entries
    2. Masking the Grid on the before load event
    The isCached method will return false if the store is empty and following code of the LiveGridView will put the grid into an infinite loop:
    Code:
        // load data if not already cached
        if (!isCached(viewIndex)) {
          if (!isMasked && grid.isLoadMask()) {
            scroller.mask(GXT.MESSAGES.loadMask_msg());
            isMasked = true;
          }
          if (loadLiveStore(getLiveStoreCalculatedIndex(viewIndex))) {
            viewIndexReload = viewIndex;
          }
          return;
        }
    If the grid is not masked manually in my code then the loop will not occur.

  8. #8
    Sencha User
    Join Date
    Nov 2010
    Posts
    90
    Vote Rating
    0
    atrubka is on a distinguished road

      0  

    Default


    I think Sencha is not going to provide a workaround.
    We'll have to wait for the next release.

  9. #9
    Sencha User
    Join Date
    Feb 2008
    Posts
    10
    Vote Rating
    0
    dali is on a distinguished road

      0  

    Default


    Quote Originally Posted by dali View Post
    I can reproduce this bug by doing the following:
    1. Returning a result of 0 entries
    2. Masking the Grid on the before load event
    The isCached method will return false if the store is empty and following code of the LiveGridView will put the grid into an infinite loop:
    Code:
        // load data if not already cached
        if (!isCached(viewIndex)) {
          if (!isMasked && grid.isLoadMask()) {
            scroller.mask(GXT.MESSAGES.loadMask_msg());
            isMasked = true;
          }
          if (loadLiveStore(getLiveStoreCalculatedIndex(viewIndex))) {
            viewIndexReload = viewIndex;
          }
          return;
        }
    If the grid is not masked manually in my code then the loop will not occur.
    Forgot to mention, that this issue is with the current release GXT 2.2.4 for GWT 2.2 it is a regression from GXT 2.2.1, I've begun upgrading to 2.2.4 and this was the first obvious problem.

  10. #10
    Sencha User
    Join Date
    Nov 2012
    Posts
    8
    Vote Rating
    0
    pitt is on a distinguished road

      0  

    Default


    The same thing happens for me with GXT 3.0.1. Any ideas why?

Thread Participants: 3