Best way of storing and manipulating simple tabular data

Hello,

What is the best way of storing and manipulating simple tabular data? I want to be able to store some integer coordinates with a string associated with them. I will frequently do the following operations:

  • Create an entry
  • Check if an entry exists
  • Delete an entry

What would be the best way of doing this? I have looked into using the H2 database potentially with JOOQ as well, but I get the impression that this is overkill for the simple set of operations that I want to do.

What would be the best way of going about this?

It seems like you might be using a hash table for this since coordinates are pretty unique. Depending on how you go about it you could just use java’s serializer to write that object to file, and read it in from file on load up. If it’s for the purpose of a plugin, where the data will only be used by 1 server at a time, and it won’t ever be touched. It’s a pretty easy way to go about it.

 private void saveOffline() throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream(PathObject.toFile());
        ObjectOutputStream objectOutputStream= new ObjectOutputStream(fileOutputStream);

        objectOutputStream.writeObject(yourHashMap);
        objectOutputStream.close();

    }

You could possibly also just save the data in hocon format or something. Some context would help provide you with a better answer. How important is this data? Why is it important that it persists?

I’m currently using Multimaps and AWT Points to store the data. My plugin is focused on land management, so chunks can have onwers. The ownership of a chunk is represented by a string for an owner associated with an AWT Point under a Multimap. I previously attempted to get a collection of all of the points for a particular owner and then convert them into JSON with Gson, but this resulted in a null pointer exception likely because even though the points were relational, the collection isn’t. I expect that the streams would have the same issue. I was considering iterating through the collection and putting all the contents of the points in a relational data structure that would allow them to be serialized, but this would make it so that I would have to overwrite the existing JSON file each time I modify the multimap. For this reason, I was looking into SQL so that I can store the data directly to disk as the plugin runs. After looking into SQL now, however, it appears to be overkill for what I want to do.

Is there a straightforward way for me to store this data to disk and append it as it changes, or should I just go with my aforementioned proposal for iterating through the points to serialize them?

Depending on how actively the owner of a chunk would change you wouldn’t be writing all that often. I’d consider storing the information in a hash map ( a multimap should be fine) with a chunk coordinate as a key and the value being an owner string. All the information would be saved probably using h2 would be easier than implementing in MySQL. Another option might be sqlite. You should write queries only for information that will be used, everything shouldn’t always be loaded. If what you were doing previously with JSON worked then why didn’t you just try to fix it. If it was throwing an NPE that can probably be addressed easily. Also if changes arent happening every second the write changes shouldn’t matter. Plus if the save queries are run asynchronously it shouldn’t matter either. If you did have the whole Data structure loaded it wouldn’t be a big deal if it’s not designed for giant servers. Or if it’s designed to be really small. But remember there can be a decent bit of overhead with bigger hashes structures. And if Workin with sql or h2 the only thing you need to save to disk are changes and new things not things that haven’t been changed.

It might be useful to create some kind of data structure that holds this information for you. Something along the lines of:

@ConfigSerializable
public class Property {

    public static final TypeToken<Property> TYPE = TypeToken.of(Property.class);

    @Setting
    private List<String> owners;
    // To be honest UUID's would probably be better, if the owner is not a player just make a new one, but it's up to you
    @Setting
    private List<Location<World>> bounds;
    // Anything within these bounds (you could do corners or something, list is generic enough to support any shape) is in the property

    /* ... code for this here, whatever you do ... */
}

And then all you have to do is load this from your config file, something like this:

Property property = node.getValue(Property.TYPE);
// or
List<Property> properties = node.getList(Property.TYPE);

And to save would just be this:

node.setValue(property, Property.TYPE);
// or
node.setValue(properties, new TypeToken<List<Property>>() {});

Where node is a ConfigurationNode holding your properties.

With this, you could store a list of properties, each holding their owners and bounds, and then save and load to any configurate supported file type, like Hocon or YAML.

If you want to be able to save any region modifications on the fly, you would want each property to have its own node, with the node name being the name of the property. That way you could save to disk without worrying about affecting other parts of the file.

If you know your regions will only be bound by a set number of coordinates it might be easier to just have that number of coordinates as fields in the object rather than a list, for quick resizing of regions.

It’s important to mention that, if this plugin is going to be used on servers with large player bases, it will be really strenuous to be constantly reading and writing to disk, especially writing. It might be more efficient to just store it into the configuration nodes, like in my example, and then perform a save on the whole file on a timed interval, and before the server stops. That way you save writes (which, if it is onto an SSD, is important) while still retaining the changes in memory as a saveable value, and can write to file on demand.