0

While using Java properties I get 2 strange errors.

customfile.properties
# of properties: 50
characters: 0-9 and English alphabet, no international characters
error 1 occurs every 200 to 500 writes
error 2 occurs every 1000 to 2000 writes

As an example, for properties:

normal_property_example_1=1234567
normal_property_example_2=8978978
normal_property_example_3=1111111
normal_property_example_4=2222222
normal_property_example_5=4444444
#... up to 50 different properties

ERROR #1
One of the properties will be corrupted, this is one of many variations:
al_property_example_4=2222222 instead of normal_property_example_4=2222222, etc.
i.e., the file will look like

normal_property_example_1=1234567
normal_property_example_2=8978978
normal_property_example_3=1111111
al_property_example_4=2222222
normal_property_example_5=4444444
#... 


For some reason a particular property name will be corrupted.
This does not happen to the whole file, only 1 or 2 properties
no exception is thrown, no I/O, no nullpointer, etc.

ERROR #2
This common error looks like a badly loaded .properties file.
the whole file will be emptied, and the current writing operation will be made.
i.e., the file will look like

 normal_property_example_4=2222222

no exception is thrown, no I/O, no nullpointer, etc.
This one I did not expect as I load the stream before writing to it.


What I think is the problem
This properties file is used to store variables that are changed very frequently.
Maybe a synchronization deadlock occurs, or maybe I need to synchronize every inner step of the read/write process.
If there is a different way to store variables that is more efficient I am welcome to suggestions.


MY CODE

WRITE

private static final Object synchLock = new Object();

public static void writePrefs(String setting, String value) {
    synchronized (synchLock) {

        File file = new File("/example/customfile.properties");

        if (!file.exists()) {
            try {
                file.createNewFile();
                file.setReadable(true, false);
                file.setWritable(true, false);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        Properties prop = new Properties();
        FileInputStream fis = null;
        FileOutputStream output = null;

        try {
            fis = new FileInputStream("/example/customfile.properties");
            prop.load(fis);
            fis.close();

            output = new FileOutputStream(path);
            prop.setProperty(setting, value);
            prop.store(output, null);
            output.close();

        } catch (IOException io) {
            sDebug("WRITE I/O EXCEPTION");
            io.printStackTrace();
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

READ

public static String readPrefs(String setting) {
    synchronized (synchLock) {

        File file = new File();
        Properties prop = new Properties();
        FileInputStream fis = null;

        try {
            if (!file.exists("/example/customfile.properties")) {
                try {
                    file.createNewFile();
                    file.setReadable(true, false);
                    file.setWritable(true, false);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            fis = new FileInputStream(path);
            prop.load(fis);
            fis.close();

            String result = prop.getProperty(setting);

            return result;

        } catch (IOException ex) {
            sDebug("READ I/O EXCEPTION");
            ex.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}


Thank you for your time.

edit
This are the methods that call the R/W operations, they are all synchronized with the same locking object.

private static final Object propertyLock = new Object();

public static String getProperty1() {
    synchronized (propertyLock) {
        String property1 = SettingsManager.readPrefs("normal_property_example_1");
        return muonium;
    }
}

public static void setProperty1(String set) {
    synchronized (propertyLock) {
        SettingsManager.writePrefs("normal_property_example_1", set);
    }
}
nick1212
  • 21
  • 8
  • Have you tried making the methods themselves synchronized? – DaveH Nov 23 '15 at 12:18
  • The R/W methods are synchronized, do you mean the methods that call the R/W methods? Yes, those are also synchronized. I will update the question with those. – nick1212 Nov 23 '15 at 12:20
  • I meant using a signature like `public static synchronized String readPrefs` - assuming readPrefs and writePrefs are in the same class – DaveH Nov 23 '15 at 12:22
  • @DaveH No, as far as I know that might introduce other issues [according to this](http://stackoverflow.com/questions/3047564/java-synchronized-method-lock-on-object-or-method?rq=1). I will try it though and get back to you. thanks – nick1212 Nov 23 '15 at 12:28
  • I wasn't able to replicate the issue using your code as posted above. When I try it it works fine (or at least seems to). But I had to write my own test harness. Would be helpful if you had a test harness that demonstrates the problem in isolation. I don't know your requirements but my instinct is that this will be very slow and a major bottleneck in your app... using a database might be a better bet. – jimjim Nov 23 '15 at 13:12
  • Can you share some more details about lock (i.e synchLock) that is being used in SettingsManager – Ashkrit Sharma Nov 23 '15 at 13:39
  • @jimjim do you mean that you recommend setting up an sqlite database for example? The reason I used java properties is because I thought that it would be much faster as it is plain text. Regarding the test harness I did not think about that, I just performed automated tests. Thank you for the idea, I will try it asap. – nick1212 Nov 23 '15 at 13:57
  • @AshkritSharma I updated the code. It is a `private static final Object synchLock = new Object();` It is used only by the methods posted – nick1212 Nov 23 '15 at 14:00
  • 1
    I guess multiple instance of your program was running and that caused corruption. On another side note on write implementation, it will re-write the whole file and will be not fast if you file gets big , you should look to write incremental data – Ashkrit Sharma Nov 23 '15 at 14:17
  • Can't really recommend anything as an alternative because I don't know your application, but based on the clues in your question (frequent update and multithreaded usecase) I would say you may find this method slow, especially because you are open/closing files a lot etc. Probably fine for a couple of threads updating occasionally, not ok for 10+ threads updating every 100ms. Feels like there is a better ways to store the state of your app - lightweight DB could work, or just recode to only save the new properties every second or something. – jimjim Nov 23 '15 at 14:18
  • I agree that multiple instances of your prog running could cause this issue. – jimjim Nov 23 '15 at 14:18
  • @AshkritSharma Thank you for your input. I did not realise that properties being fully rewritten could be part of the problem. I will rewrite the whole class and use a lightweight DB (sqlite). – nick1212 Nov 23 '15 at 14:54
  • @jimjim Thanks. Yes, use case scenario is frequent update and read of approximately 100 ms in a multithread between different java packages. Thank you all again for your help – nick1212 Nov 23 '15 at 14:56

0 Answers0