RFC - Reduce loading of PropertiesFile

Thomas Meyer thomas at m3y3r.de
Sun Apr 15 13:03:06 PDT 2012


Am Donnerstag, den 12.04.2012, 15:11 +0200 schrieb Jiri Vanek:
> Hi!

Hey!

> diffs as attachments and changelogs as plaintext please :)

oops! Yes, sorry. Here you go:

2012-04-15  Thomas Meyer <thomas at m3y3r.de>

	* netx/net/sourceforge/jnlp/util/PropertiesFile.java
	Reduce no. of disk accesses in (load) when the recently_used file was not
	changed since the last (store).
	* netx/net/sourceforge/jnlp/cache/CacheLRUWrapper.java: (load)
	Avoid call of (checkData), when file was not changed.

New patch(es) against tip as attachment.

> 
> Idea looks excelent, but several issues inline:
> 
> On 04/10/2012 09:54 PM, Thomas Meyer wrote:
> > diff -r 60ef5191add3 netx/net/sourceforge/jnlp/cache/CacheLRUWrapper.java
> > --- a/netx/net/sourceforge/jnlp/cache/CacheLRUWrapper.java	Tue Apr 10 19:10:43 2012 +0200
> > +++ b/netx/net/sourceforge/jnlp/cache/CacheLRUWrapper.java	Tue Apr 10 21:49:08 2012 +0200
> > @@ -108,11 +108,11 @@
> >        * Update map for keeping track of recently used items.
> >        */
> >       public synchronized void load() {
> > -        cacheOrder.load();
> > +        boolean loaded = cacheOrder.load();
> >           /*
> >            * clean up possibly corrupted entries
> >            */
> > -        if (checkData()) {
> > +        if (loaded == true&&  checkData()) {
> +        if (loaded && checkData()) {
> please ;)
> (unless it somehow destroy difference between && and & O:) )

&& is the right thing to do here! we want to avoid the call of
checkData(), when the file was not reloaded.

> 
> >               if (JNLPRuntime.isDebug()) {
> >                   new LruCacheException().printStackTrace();
> >               }
> > @@ -125,7 +125,7 @@
> >       /**
> >        * check content of cacheOrder and remove invalid/corrupt entries
> >        *
> > -     * @return true, if cache was coruupted and affected entry removed
> > +     * @return true, if cache was corrupted and affected entry removed
> >        */
> >       private boolean checkData () {
> >           boolean modified = false;
> > diff -r 60ef5191add3 netx/net/sourceforge/jnlp/util/PropertiesFile.java
> > --- a/netx/net/sourceforge/jnlp/util/PropertiesFile.java	Tue Apr 10 19:10:43 2012 +0200
> > +++ b/netx/net/sourceforge/jnlp/util/PropertiesFile.java	Tue Apr 10 21:49:08 2012 +0200
> > @@ -35,6 +35,9 @@
> >
> >       /** the header string */
> >       String header = "netx file";
> > +
> > +    /** time of last modification */
> > +    long lastStore;
> >
> >       /** lazy loaded on getProperty */
> >       boolean loaded = false;
> > @@ -104,24 +107,32 @@
> >        * Ensures that the file backing these properties has been
> >        * loaded; call this method before calling any method defined by
> >        * a superclass.
> > +     *
> > +     * @return true, if file was (re-)loaded
> > +     *         false, if file was still current
> >        */
> > -    public void load() {
> > +    public boolean load() {
> >           loaded = true;
> Looks like unused?

No. This is an already present optimisation to lazy load the file on the
first call of getProperty().

> >
> > -        InputStream s = null;
> > -        try {
> this
> > -            if (!file.exists())
> > -                return;
> should remains here, returning false, as you are testing file.lastModified() later
okay.

> 
> > +        if(lastStore == 0 || lastStore>  0&&  file.lastModified() != lastStore) {
> I believe this lastStore>  0 is redudat:
> if(lastStore == 0 || file.lastModified() != lastStore)
> will do the same thing?

lastModified() tells:
"returns [...] 0L if the file does not exist or if an I/O error occurs"

lastStore will be zero as it is initialised at object creation time.

so I wanted to make sure to at least try to load the file once.
does that makes sense?

> 
> > +            InputStream s = null;
> > +            try {
> this
> > +                if (!file.exists())
> > +                    return false;
> will be redundant then (^^^)

okay.

> > +
> > +                try {
> > +                    s = new FileInputStream(file);
> When you are touching this, I believe the encoding of this file should be during storing and loading 
> namely specified as utf-8 (icedtea-web have issues with encodings... so its better to start sooner 
> then later)

FileInputStream is a byte stream, so no character set is interpreted
here. also the class PropertiesFile is an subclass of Properties.

Properties.load() tells:

"Reads a property list (key and element pairs) from the input byte
stream. The input stream is in a simple line-oriented format as
specified in load(Reader) and is assumed to use the ISO 8859-1 character
encoding; that is each byte is one Latin1 character. Characters not in
Latin1, and certain special characters, are represented in keys and
elements using Unicode escapes."

so I think we should not use a different character set here.

> > +                    load(s);
>        *1 (see below ;)
> > +                } finally {
> > +                    if (s != null) s.close();
> > +                }
> > +            } catch (IOException ex) {
> > +                ex.printStackTrace();
> return false here?

yes, of course. fixed.

> > +            }
> > +            return true;
> no return here here
> > +        }
> >
> > -            try {
> > -                s = new FileInputStream(file);
> > -                load(s);
> > -            } finally {
> > -                if (s != null) s.close();
> > -            }
> > -        } catch (IOException ex) {
> > -            ex.printStackTrace();
> > -        }
> > +        return false;
> shouldn't  there be return true/nothing (returns already solved) - considering my hints are valid?
> >       }
> >
> >       /**
> > @@ -137,6 +148,7 @@
> >                   file.getParentFile().mkdirs();
> >                   s = new FileOutputStream(file);
> >                   store(s, header);
> > +                lastStore = file.lastModified();
> This is shouldn't be there. I would like to move lastStore = file.lastModified(); to load function. 

fixed.

> or  to "*1" location (because reason of this timestamp is also external modification of recently_used)
> >               } finally {
> >                   if (s != null) s.close();
> >               }
> >
> >
> Little bit of-the-basin think - are you sure that store() as it is written changes lastModified() 
> linux stamp correctly? (I had some bad experiences with this, but have never examined it separately)

no. a fsync() was missing here. fixed.

> 
> Also I would like to suggest at least two tests with this patch
> 1) generate eg 1mb recently_used file and measure set some deadline how fast javaws  have to start. 
>    The value should be failing without this patch, and  passing with this one applied. Also some 
> real number how faster this is will be much appreciate!
> 
> 2) second one will be little bit more difficult. It would be nice to test, that when recently_used 
> is modified during javaws run, then it reloads it correctly. And so verify that this patch will not 
> cause some regression.
> 
> 
> Maybe unittest will be easier to prepare instead of 2)
> But I'm afraid those (or similar ) tests will be really necessary.

I'll write some test cases and will get some figures.

> What do you think?

sounds good to me.

> 
> btw - there is task[1] which have long-term goal to rewrite cache subsystem. Do you want to be 
> volunteer?

Sorry, but I can only do some small contributions, as this is just a
hobby for me. This sounds more like a full-time job...

with kind regards
thomas

-------------- next part --------------
A non-text attachment was scrubbed...
Name: reduce-load.patch
Type: text/x-patch
Size: 6642 bytes
Desc: not available
Url : http://mail.openjdk.java.net/pipermail/distro-pkg-dev/attachments/20120415/0e72f3a3/reduce-load.patch 


More information about the distro-pkg-dev mailing list