PSTORE and me: An uneasy alliance

written in flatiron school, ruby

EDIT: I literally wrote this post the day before I learned what SQL was. Oh the folly of youth.

In the beginning…

Earlier in the week, when working on a little NBA player stats CLI program, I had my first run in with Ruby’s PSTORE class - a mechanism that allows you store Ruby objects that persist between instances of the program running. The program we were building let you build a team of ten basketball players, and we wanted a way for the program to remember your team the next time it started up.

After some wrangling, I got PSTORE to work. The program could save an array of Ruby objects upon shutting down (in this case individual basketball players), and then return that same array upon the next startup. I felt great. I felt triumphant!

…but I got it to work in the same way that primitive man got fire to ‘work’.

Primitive man's experience with PSTORE

Sure, those hirsute cave dwellers weren’t freezing to death, but they also weren’t bandying about high level concepts of thermodynamics. And so, like my primordial kin, I stared into the crackling PSTORE flames, my eyes wide with abject miscomprehension and distrust.

I knew what needed to be done. I needed to wade into PSTORE, to cleanse myself in its waters and emerge a more competent, capable web developer.

Cool. Wait. What is this PSTORE you speak of?

So, first thing’s first. What exactly is PSTORE? I think if you were to ask a random person on the street, they might say:

PStore implements a file based persistence mechanism based on a Hash. User code can store hierarchies of Ruby objects (values) into the data store file by name (keys). An object hierarchy may be just a single object. User code may later read values back from the data store or even update data, as needed.

…if by “random person on the street” you meant “the Ruby documentation.” So what does it mean? It means you can ‘persist data’ - using PSTORE you can save Ruby objects (in our case, an array of basketball players) to be accessed during a different through a Hash-like structure. Our array was stored as the value for a key called :players. This hash was saved to a .pstore file included in our project.

Getting started with PSTORE (or How I Learned to Stop Worrying and Love the Persistent Hash)

PSTORE is part of the standard library, so it can be used by incuding by simply requiring it. No need for pesky gems or ancient voodoo incantations! After that, you need to initialise a new PSTORE object, passing the desired path of the .pstore file as the argument.

1
2
require 'pstore'
saved_data = PSTORE.new("filepath.pstore")

The cool thing about this, is that PSTORE detects if the file already exists. If it does, it reads the data in the file and assigns it to the saved_data variable. If not, it creates a new file and assigns it. So, at this point, the value of saved_data is now a persistent hash. Neato.

In our case, we did that as soon as the program first started, in the first method called by our program. Now, when you actually want to read or write to the .pstore file, you need to do within a ‘transaction’. Transactions are an instance method of the PSTORE class.

Transactions - Cha-Ching!

So, let’s say we wanted to save to the .pstore file. How would we do this?

1
2
3
saved_data.transaction do
  saved_data[key_name] = [key_value]
end

This code assigns a value, key_value to a key, :key_name in the PSTORE hash object. The value could be an number of different types of Ruby objects. In the case of our project, it was an array of basketball players.

To read from the .pstore file, and assign its value to a variable that we can use in Ruby, we follow a similar strategy.

1
2
3
some_variable = saved_data.transaction do
  saved_data.fetch(:key_name, default)
end

A number of things are happening here. Like the method of saving, we call the #transaction method on saved_data. We use the fetch method to retrieve the value of a particular key (:key_name). The default option is what we will return if no such key is present. Great!

So why do we have to do this in a transaction? If you try with the transaction, Ruby returns an error. Well, from what I understand, this is to ensure that multiple processes don’t access the same .pstore file at the same time, avoiding data being written in an incomplete or corrupted state.

Conclusion: PSTORE is rad and I also I don’t fully understand it

My understanding of PSTORE is way more advanced than it was a few short days ago, but it’s still not…great. There’s something called ‘commit’, which seems to be a method of finalising the tasks being done in a transaction, but I haven’t figured it all out yet. But I’ll keep trying.

I guess I’m no longer a prehistoric human, staring at a fire and failing to understand what it is. I know what fire is. I think. I just don’t know how it fully works. Or why it fully works. So, I guess in terms of of human history, I’m somewhere in Ancient Greece.

And that’s not nothing.

The Ancient Greek's knowledge of fire is akin to my knowledge of PSTORE now.

Sources

Roblog: Persisting data in Ruby with PStore

Codebar: The basics: Storing data - PSTORE