Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug in deletePrefix(). #3

Closed
boxymoron opened this issue Jun 25, 2024 · 9 comments
Closed

Bug in deletePrefix(). #3

boxymoron opened this issue Jun 25, 2024 · 9 comments
Labels
bug Something isn't working

Comments

@boxymoron
Copy link

The implementation of deletePrefix() is akin to removing an item from an array while iterating (i.e. doesn't work).
Possible Fix?:

public deletePrefix(prefix: string): void {
  Object.keys(this.ls).filter(k => k.startsWith(prefix) && k !== this.recentKey).forEach(k => {
    this.deleteUsage(k);
    this.ls.removeItem(k)
  });
}
@williamstein
Copy link

Your suggestion looks good to me, except with

try {
      this.deleteUsage(key);
      this.ls.removeItem(key);
    } catch (e) {
      console.warn(`localStorage: delete error -- ${e}`);
    }

to maintain the same semantics.

@williamstein
Copy link

@boxymoron do you want to make a PR?

@haraldschilly haraldschilly added the bug Something isn't working label Jun 26, 2024
@haraldschilly
Copy link
Contributor

I've created a PR, so far just modified the test. I think I understand your point, but my test doesn't trigger a problem. Maybe I'm confused 🤔

#4

haraldschilly added a commit that referenced this issue Jun 26, 2024
@haraldschilly
Copy link
Contributor

@boxymoron ok. can you please check my #4 PR?

@boxymoron
Copy link
Author

boxymoron commented Jun 26, 2024

@haraldschilly
Try running this in a browser (I used the latest Firefox):

console.log('Begin LocalStorageLRU.deletePrefix() test:')
      console.log('clearing localStorage...')
      window.localStorage.clear();
      console.log('window.localStorage.length: ', window.localStorage.length);
      lsLRU = new LocalStorageLRU({
        maxSize: 512,
        recentKey: 'myKey',
        fallback: false,
      });
      
      lsLRU.set('foo', 'bar');
      for(let i=0; i<100; i++){
        lsLRU.set('test-'+i, i)
      }
      console.log('lsLRU.size(): ', lsLRU.size(), ', should be 101');
      
      console.log('calling LocalStorageLRU.deletePrefix()')
      lsLRU.deletePrefix('test-');
      console.log('lsLRU.size(): ', lsLRU.size(), ', should be 1')

The output is:

Begin LocalStorageLRU.deletePrefix() test:
clearing localStorage...
window.localStorage.length:  0
lsLRU.size():  101 , should be 101
calling LocalStorageLRU.deletePrefix()
lsLRU.size():  50 , should be 1

Also, I found another issue, LocalStorageLRU.clear() calls localStorage.clear(). While this is documented with a comment as such, I think it is problematic, as users of the library probably expect it to only clear entries "managed" by LocalStorageLRU, while it clears everything in localStorage (including key/values that were not "managed" by LocalStorageLRU). Maybe this merits another PR?

@haraldschilly
Copy link
Contributor

@boxymoron so, thank you for explaining this. Version 2.5.0 is released. Can you please check if this works for you?

Regarding clear(): yes, this lib is kind of a complete take over. Maybe this should be explained in the readme a little bit more? There is no tracking of which keys this lib has under its control. It's also using existing entries that already existed.

The only thought I have is: there could be a default prefix (by default, there is none, to match the current behavior) and all get/set/delete ops add that common prefix to all keys automatically. That way, this lib would have its own "namespace".

@boxymoron
Copy link
Author

@haraldschilly Aren't all the keys tracked in the recentKey entry itself? You should be able to do something like:

localStorage.getItem(recentKey).split(delimiter).forEach(k => localStorage.removeItem(k));

@boxymoron
Copy link
Author

@boxymoron so, thank you for explaining this. Version 2.5.0 is released. Can you please check if this works for you?

Regarding clear(): yes, this lib is kind of a complete take over. Maybe this should be explained in the readme a little bit more? There is no tracking of which keys this lib has under its control. It's also using existing entries that already existed.

The only thought I have is: there could be a default prefix (by default, there is none, to match the current behavior) and all get/set/delete ops add that common prefix to all keys automatically. That way, this lib would have its own "namespace".

@haraldschilly Yes, it's working correctly now. Thank you for updating.

@haraldschilly
Copy link
Contributor

@haraldschilly Aren't all the keys tracked in the recentKey entry itself?

well, no, only the recent ones. It's used by the trim() method, and well, the background of all that is to implement an LRU cache – hence the name. The root problem we faced was, when the local storage gets full, exceptions are thrown, you can't save anything new anymore. This wrapper records recent usage (keys) and updates the list of recent keys. If that update fails, it issues a trim operation (which heuristically removes some entries, but not the recent ones). Hence, it is always possible to save/update keys, while it eventually forgets some of the old stuff. The due to all that, performance penalty is very small, and the storage overhead is constant (and very minimal as well).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants