My workaround for a daily ZRAM Sync of Openhab rrjd persistance

Here my rather lengthy post about what I did to use ZRAMs daily sync:

Motivation:

  1. After a power failure OpenHABs persistence is lost up to point in time when ZRAM did last syncronize the persistence folder to SD card.
  2. After a power failure ZRAM does not start - see: https://github.com/ecdye/zram-config/issues/142 but mentioned fix did not work for me.
  3. Current default ZRAM config for OpenHAB does not allow online ZRAM sync - Openhab service is stopped and after Zsync started again. I dont like that.
  4. When doing a “online” ZRAM sync OpenHAB RRD4j and MapDB persistance may fail - no system likes messing with files it wants to acces, results in loss of data.
  5. When doing a “online” ZRAM sync OpenHAB logging to openhab.log file will stop . (But it may be waken up by Karaf console e.g. by command log:tail).

My Setup:

Openhab 5.1.4 on a Raspi 4 with 2 GB of RAM.
This was set up by using OpenHABian v1.11.0. 32GB SD Card.
RaspiOS: Release = Debian GNU/Linux 12 (bookworm) , Kernel = Linux 6.6.62+rpt-rpi-v8
app. 800 Items, app. 500 items are persisted by RRD4j by every6sec and restoreOnStartup strategy. No other persistence service is running.

Workaround overview:

  1. Modify zram-config so OpenHAB service is not restated.
  2. ZRAM sync just the folder holding persistance database files.
  3. Pause RRD4j persistence logging to allow safe online Zram sync.
  4. Create a systemd timer and service to ZRAM sync once each day.
  5. Detect if Raspi was restarted right after a power fail and do a 2nd (clean) restart if so.

If you plan to implement the workaround it is time now to do some kind of backup - e.g. OpenHAB config backup using “sudo openhab-config” and menue pt. 50

Workaround steps in detail:

1) Modify zram-config so OpenHAB service is not restated running “zram-config sync”.
Default Openhabian setting for ZRAM sync will stop all related services to do a clean syncronisation to SD card.
For sure this is the safest/cleanest way to do a sync, but I really dont like that so many services are pulled down and started up again. Things can go wrong during service startups, clients may not be logging in,…
1.1) Change zram-config file to not shut down OpenHAB and related services:
I am using default zram-config from ZRAM-config github from here: zram-config/zram-config at main · ecdye/zram-config · GitHub
This can be done like this:
1.1.1) Log into host (openhabian) running OpenHAB.
1.1.2) Stop OpenHAB service: sudo systemctl stop openhab.service
1.1.3) Stop ZRAM service: sudo systemctl stop zram-config.service
Check if ZRAM stopped clean: zramctl … should not give any response, if yes delete listed “ghost” zram device e.g. sudo rm /dev/zram2
1.1.4) Remove zram-config file: sudo rm /usr/local/sbin/zram-config
1.1.5) Create a new one, copy the github zram-config to /usr/local/sbin/zram-config or use nano editor: sudo nano /usr/local/sbin/zram-config
1.1.6) paste all the content of zram-config/zram-config at main · ecdye/zram-config · GitHub and finish nano editor with “strg + X” and y to save
1.1.7) Make zram-config executable: sudo chmod 777 /usr/local/sbin/zram-config

2) Modify zram-sync to syncronize just the folder holding persistance database files.
ZRAM sync allows to add a target folder option for syncronisation - I just want to syncronize /var/lib/openhab/persistence
Also stop rrd4j persistence from writing to persistance rrd files during syncronisation (see also next pt. 3)
2.1) Create special zram-sync bash script: zram-oh-persistence-sync
This can be done like this using nano editor:
2.1.1) sudo nano /usr/local/sbin/zram-oh-persistence-sync
2.1.2) paste following text:

#!/usr/bin/env bash
cp /etc/openhab/persistence/rrd4j-empty.txt /etc/openhab/persistence/rrd4j.persist
echo "Persistence strategies emptied...now waiting 30 sec"
sleep 30
/usr/local/sbin/zram-config sync /var/lib/openhab/persistence
echo "Finished running: /usr/local/sbin/zram-config sync /var/lib/openhab/persistence ...now waiting 60 sec"
sleep 60
cp /etc/openhab/persistence/rrd4j-ok.txt /etc/openhab/persistence/rrd4j.persist
echo "Persistence strategies restored"
exit 0

2.1.3) A strg + X followed by y …saves the file
2.1.4) sudo chmod 777 /usr/local/sbin/zram-oh-persistence-sync … sets it executable

3) Pause RRD4j persistence logging to allow safe online Zram sync.
The idea is to temporerally persist no items during zram-sync and persist normally when zram-sync is done.
Persistence in OpenHAB can be defined via UI or via a setup file for rrd4j called: /etc/openhab/persistence/rrd4j.persist.
If the setup file exists it is used. Changes in persistence via UI is disabled. Changes in setup file are taken into account on the fly.
So 2 files must be created one for no persistance and one for your normal persistance strategies setup.
3.1) Create a file which will persists zero items - used during syncronisation
3.1.1) sudo nano /etc/openhab/persistence/rrd4j-empty.txt
3.1.2) paste following text:

Strategies {
    every6sec : "0/6 * * * * ? *"
}
Items {
    // File: /etc/openhab/persistence/rrd4j.persist
    // Temporarily left empty to pause persistence
}

3.1.3) A strg + X followed by y …saves the file

3.2) Create a file which will persists all items/groups you want persisted. (Here my file, change to your needs !)
3.2.1) sudo nano /etc/openhab/persistence/rrd4j-ok.txt
3.2.2) paste following text (Thats the file I use, change to your needs):

Strategies {
    every6sec : "0/6 * * * * ? *"
}
Items {
    // File: /etc/openhab/persistence/rrd4j.persist
    // Persist all Items from these Groups
        Elektroheizung*, Energiemessung1*, GoeCharger*, Heizung*, PV_Wechselrichter*, RaspberryPi*, Raum1_Thermometer*, Raum2_Thermometer*, Raum3_Thermometer*, Shelly_Heizung*, Stadel_PV*, Stromzaehler*, Thermische_Solaranlage*, Warmwasser_Boiler*, Wasserpumpe* : strategy = every6sec, restoreOnStartup
}

3.2.3) A strg + X followed by y …saves the file

I had to switch from UI persistence setup to file based persistance setup.
First I created a correct /etc/openhab/persistence/rrd4j.persist file which reflected UI setup. Then restarted OpenHAB so persistence switched over to file based setup.
Now call up UI page for persistence and go to RRD4j configuration. If it looks like you still are able to do modifications via UI you should correct this:
Press red Remove persistence configuration link at the bottom of the config page and OK the popup and finally Save (upper right corner).
Calling up the RRD4j Config page again should show now: Note: This persistence configuration is not editable because it has been provisioned from a file.
Check OH documentation for persistence here: Persistence | openHAB

4) Create a systemd timer and service to ZRAM sync once each day.
The above created /usr/local/sbin/zram-oh-persistence-sync file has to be started once a day to do syncronisation.
So 2 systemd files are created one timer and one service file called by the timer
4.1) Create new zsync timer systemd file
4.1.1) sudo nano /etc/systemd/system/zsync-oh-persistence.timer
4.1.2) paste following text

[Unit]
Description=Perform nightly zram sync to persistent storage (only OpenHab Persistence)

[Timer]
Unit=zsync-oh-persistence.service
OnCalendar=*-*-* 23:15
RandomizedDelaySec=10m
Persistent=true

[Install]
WantedBy=timers.target

4.1.3) A strg + X followed by y …saves the file
So with this timer the sync takes place at around 23:15 , you may change this to your needs.

4.2) Create new zsync service systemd file
4.2.1) sudo nano /etc/systemd/system/zsync-oh-persistence.service
4.2.2) paste following text

[Unit]
Description=Perform nightly zram sync to persistent storage (only OpenHab Persistance)
After=zram-config.service
Wants=zsync-oh-persistence.timer

[Service]
Type=oneshot
Environment=SERVICE=1
ExecStart=/usr/local/sbin/zram-oh-persistence-sync

4.2.3) A strg + X followed by y …saves the file

4.3) Enable and start the new timer and service file
4.3.1) sudo systemctl start zsync-oh-persistence.timer
4.3.2) sudo systemctl enable zsync-oh-persistence.timer
4.3.3) sudo systemctl daemon-reload

5) Detect if Raspi was restarted right after a power fail and do a 2nd (clean) restart if so.
When a power fail occurs there is a high chance that ZRAM will not start up correctly.
This happenes on my system and is also described here: Zram is not loaded after a power outage · Issue #142 · ecdye/zram-config · GitHub
The mentioned fix did not work for me, so following my brutal fix…to detect power fail and restart a 2nd time if booting was after a power failure
At Raspi startup a file is checked for existance and gets created. At an orderly shutdown this file gets deleted.
So if this file exist at startup boot up was right after a power fail and a reboot command is fired up.
5.1) Create a bash script to do the “magic” decribed above.
5.1.1) sudo nano /bin/powercheck
5.1.2) paste following text

#!/bin/sh

FLAG1=/etc/poweroff-flag-file
FLAG2=/etc/bad-reboot-flag-file

if [ "$1" = "start" ]; then
  if [ -f "$FLAG1" ]; then
    echo "Detected impropert shutdown" >&2
    (
    echo 'Detected improper reboot'
    rm -f $FLAG1
    echo "Power fail detected" > $FLAG1
    rm -f $FLAG2
    echo "Power fail detected" > $FLAG2
    echo "So reboot now again..." >> $FLAG2
    date >>  "$FLAG2"
    reboot
    )
  fi

  date >>  "$FLAG1"
elif [ "$1" = "stop" ]; then
  rm -f $FLAG1
fi

5.1.3) A strg + X followed by y …saves the file
5.1.4) sudo chmod 777 /bin/powercheck … sets it to executable

5.2) Create a systemd service to have the bash script run a boot and shutdown.
5.2.1) sudo nano /etc/systemd/system/powercheck.service
5.2.2) paste following text

[Unit]
Description=Detect if system was shut down cleanly
After=network.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/powercheck start
ExecStop=/bin/powercheck stop

[Install]
WantedBy=multi-user.target

5.2.3) A strg + X followed by y …saves the file
5.2.4) sudo systemctl start powercheck.service
5.2.5) sudo systemctl enable powercheck.service
5.2.6) sudo systemctl daemon-reload

Its also a good idea to finally reboot your OpenHAB host using : sudo reboot

Notes:

  1. I did test 15 times a zram-sync followed by a power fail - all ok, no loss of data. And about 60 times a zram-sync which is done then automatically on a daily basis - all ok.

  2. Actual zram-config included a “bind_dir” folder in /etc/ztab config file. This is now removed, automatically if old version of ztab is detected.

    See: GitHub - ecdye/zram-config: A complete zram-config utility for swap, directories, and logs to reduce SD, NAND and eMMC block wear. · GitHub

  3. I deleted MapDB persistance and only use now RRD4j - also to restore items on startup (Strategy: restoreOnStartup). My tests where showing that MapDB stops working once it is “online” synced. Keep in mind that RRD4j just saves numbers and status of switches.

  4. I changed also my ztab file (very optional - zram must be stopped during editing!), my /etc/ztab file looks like this:

# swap	alg		mem_limit	disk_size	swap_priority	page-cluster	swappiness
swap	lzo-rle		200M		1G		75		0		150

# dir	alg		mem_limit	disk_size	target_dir		
dir	lzo-rle		800M		2G		/var/lib/openhab/persistence

# log	alg		mem_limit	disk_size	target_dir			oldlog_dir
log	lzo-rle		400M		1G		/var/log

Did now some corrections:

  • It’s called persistent and not persistant (pardon my denglish)
  • systemctl commands for zsync-oh-persistence.service removed (not needed)
  • Migration from UI based to file based persistence refined.

Can you please submit this as a PR to openHABian so everybody can benefit?

I doubt #3 is required, plus for a general setup there’s more OH parts / 3rd party systems such as InfluxDB that access zram mounts.
So make that optional and discuss on Github upfront cc:@ecdye.

Regarding Pt. 3 - pausing RRD4j from writing:
During testing I did see problems when not doing it.
A zsync without was resulting in empty RRD4j .rrd database files for some of my 500 persisted items. Not on every zsync, I would say there was a 25% chance to loose RRD4j data.

To make this more suitable for other setups I plan to test also how MapDB is doing. Since I don’t have others persistence running I was hoping on community involvement …
For sure InfluxDB would be an important persistense to test.

Be aware that rrd4j can only restore numeric states. All items that are not Number or OnOff types cannot be restored (e.g. Color lights).

Added now MapDB as an option. But had not time to do Zsync tests … will follow.

Did now some quick tests with MapDB active during “online” (OpenHAB running) zram syncronisation. Bad news…once zram syncs MapDB does not come to life any more. The timestamps of the storage.mapdb files do not change any more and no data is saved.
Trying to halt MapDB from writing by changing to a “empty” mapdb.persist file is no problem. While mapdb.persist is not containing any items also the timestamps do not change, but return to life once items are implemented again.

Seems that MapDB is not so “forgiving” messing around with its files as RRD4j is.

So I remove the MapDB option …