Exadra37

Exadra37

Mnesia with Memento lost all records for all tables

I have been developing an app in localhost, while keeping a staging version of the app running in another folder, with mix phx.server, that I use daily.

So, each time I shutdown or restart the laptop I don’t bother to manually stop it, but today I have stopped it accidentally with ctrl + c + c, and for my surprise when I started it again all my tables were empty :dizzy_face: :exploding_head:

This was not the first time I have used ctrl + c + c to stop it, but never had this outcome.

I am using disc_copies tables, and I am not running in clustered mode.

application.ex:

  def start(_type, _args) do
    # Create the Schema
    Memento.stop
    Memento.Schema.create([node()])
    Memento.start

    # Create the DB with Disk Copies
    # @TODO:
    # Use Memento.Table.wait when it gets implemented
    # @db.create!(disk: nodes)
    # @db.wait(15000)
    Memento.Table.create!(Users, disc_copies: nodes)
   
    # omitted usual code

end

So what can I do to pinpoint the cause of this catastrophic lost?

Most Liked

keathley

keathley

Inspired by some of the discussions on this thread, I decided to play around with different failure modes with mnesia distribution: https://github.com/keathley/breaking_mnesia. I have a large test file that tries to explain my thought process. A cynical person could probably claim that these “failures” are either “working as intended” or “operator error”. My point wasn’t to try to say that mnesia is broken. My goal was to demonstrate the ways that Mnesia might be surprising if you’re expecting it to provide certain guarantees.

derek-zhou

derek-zhou

You can make some simple API so you can access the app from the outside using curl or something simple. You need 2 API access:

  1. check data integrity, return ok or not
  2. do some random read write

Then you can make a shell script with an infinite loop:

  1. mix phy.server
  2. check integrity. If failed, stop right here
  3. random access
  4. kill -9

Then you can run it over night to see if you can trigger something.

vans163

vans163

The first thing that comes to mind is the node name changed, so the schema path changed. Like running
iex -S mix
then running
iex --sname test -S mix

The idea behind Mnesia is you MUST run it in at least 2 node configuration, as all writes go to both nodes, if 1 node has a power problem / CTRL+C+C, the other node will still receive the writes. (So 3 nodes total, your app + 2 noded mnesia). If you trip over the powercord to the rack hosting both nodes you are screwed and will lose (alot of) data.

Mnesia has no writeaheadlog like (all?) modern databases, it uses a log but its just an in-ram log that gets periodically flushed to disk. (This is why rocks_db backend for Mnesia is not a real solution to me, it doesnt add a WAL)

There was ways around it, you can set the logdumpthreshold to 1 millisecond, so mnesia will dump the log every 1ms. Or set it to 1 write (default is 1000 i think). But dumping this log is very cpu intensive and your tables will lock up as the dump is done, large tables will be rendered unwritable.

If you want to run Mnesia in a single local node configuration (just to store some persistent state for your app in a simple way), id run it with logdumpthreshold 1 write.

cmkarlsson

cmkarlsson

To me it sounds like a new set of schema was created so make sure that:

  • node name has not changed
  • The path to the mnesia files have not changed (look for :mnesia configuration options)

In case the path and node name are correct you can check the status of mnesia itself:

You can check the status of mnesia with :mnesia.system_info(), :mnesia.info(). See man pages for mnesia for more information, or perhaps this page: https://erlang.org/doc/apps/mnesia/Mnesia_chap7.html

You can look for an mnesia core dump to figure out if something crashed. They are called MnesiaCore.<nodename>.<when>.

A quick comment on your startup code. You should generally only create the schema and table once, not every startup. This is also mentioned in the Memento documentation. I don’t know if that has anything to do with your problem (likely not) but something you should consider before moving into production.

cmkarlsson

cmkarlsson

Well, it wasn’t necessarily you who changed it :smiley: so don’t write this off until you can confirm it is not the problem.

As an example from the memento configuration:

# config/config.exs
config :mnesia,
  dir: '.mnesia/#{Mix.env}/#{node()}'        # Notice the single quotes

Which means if you change node name or your mix env you will end up with a different directory.

I don’t know if you followed this configuration but that could give an idea why something would change.

Regarding :mnesia.system_info I would probably just check that the directory is what you expect, that the node is started and accessible and that the tables are of the type you expect.

Interactive Elixir (1.10.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Memento.stop

14:34:19.460 [info]  Application mnesia exited: :stopped
:ok
iex(2)> Memento.Schema.create([node()])
:ok
iex(3)> Memento.start()
:ok
iex(5)> :mnesia.system_info()
===> System info in version "4.16.1", debug level = none <===
opt_disc. Directory "/home/martink/mnesia/what/Mnesia.nonode@nohost" is used.
use fallback at restart = false
running db nodes   = [nonode@nohost]
stopped db nodes   = []
master node tables = []
remote             = []
ram_copies         = []
disc_copies        = [schema]
disc_only_copies   = []
[{nonode@nohost,disc_copies}] = [schema]
2 transactions committed, 0 aborted, 0 restarted, 0 logged to disc
0 held locks, 0 in queue; 0 local transactions, 0 remote
0 transactions waits for other nodes: []

Gives you some information. Especially the Directory "/home/martink/mnesia/what/Mnesia.nonode@nohost" is used line shows you where you store the mnesia datafiles.

You can also double-check that the node is started and that the tables are in fact in :disc_copies mode.

If you search for schema.Dat you might find others mnesia schemas being created.

I don’t think so but perhaps if there is some funny race condition? Normally mnesia will detect that there is a database there already and give you and already_exists error.

Where Next?

Popular in Questions Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
makeitrein
Hey all, just started picking up Elixir last week and am writing a scraper as a learning project. Baby step #1 is extracting the number ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
hpopp
To simplify some tasks at work, I wrote and published this package yesterday. It’s a simple macro that enables Access behaviour on struct...
New
Codball
Mix format works fine if run from the cmd. I’ve followed this to facilitate the implementation into VSC which involves downloading an ext...
New
jc00ke
Expanding on this topic: https://forum.elixirforum.net/t/map-typespec-question/19217 Let’s say I have a map with required and optional k...
New

Other popular topics Top

lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1140 51847 244
New
yurko
Here are few pieces of (common) Linux knowledge that we use for reasonably small one server apps. We use Ubuntu but this should work for ...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement