Thursday 30 November 2023

Refactoring

So, I saw some code that I didn't like, and I decided to refactor it.

The code was thusly.

public boolean onLeave() {
    boolean valid = super.onLeave();
    Account account = database.getAccount();
    ShoppingList shoppingList = database.getShoppinglist(account);
    if (valid) {
      valid = !shoppingList.isEmpty();
    }
    if (valid) {
      valid = !blockedAccounts.contains(account);
    }
    if (valid) {
      String country = account.getPerson().country();
      valid = webshop.alsoShipsTo(country);
    }
    if (valid) {
      valid = account.hasCreditcardAttached() ||
          account.hasPrepaidcardAttached() ||
          account.hasCash();
    }
    return valid;
  }

And I thought to myself, it's really just a list of expressions, where each one is evaluated until you find one that evaluates to false, and then you stop.

So, that's basically a Stream where you filter out all the "false" values, and get the first one.

So, I decided to refactor it just like that.

public boolean onLeave() {
    Account account = database.getAccount();
    ShoppingList shoppingList = database.getShoppinglist(account);

    List<Supplier<Boolean>> checks = new ArrayList<>();
    checks.add(super::onLeave);
    checks.add(() -> !shoppingList.isEmpty());
    checks.add(() -> !blockedAccounts.contains(account));
    checks.add(
        () -> {
          String country = account.getPerson().country();
          return webshop.alsoShipsTo(country);
        });
    checks.add(() -> account.hasCreditcardAttached() ||
        account.hasPrepaidcardAttached() ||
        account.hasCash());

    return checks.stream()
        .filter(t -> t.get().equals(Boolean.FALSE))
        .findFirst()
        .isEmpty();
  }

I proudly showed this to my colleagues, and they immediately shook their heads in disgust.

Apparently, in my eagerness to use Lambdas and Streams and all that cool stuff, what I really had done is recreated the short-circuit version of an If statement in Streams.

I find myself turning to Lambdas and Streams when in reality these are not needed, and my eventual solution works fine without them.

So, rewriting this as a short-circuited IF statement looks like this:

public boolean onLeave() {
    Account account = database.getAccount();
    ShoppingList shoppingList = database.getShoppinglist(account);

    return super.onLeave() &&
        !shoppingList.isEmpty() &&
        !blockedAccounts.contains(account) &&
        webshop.alsoShipsTo(account.getPerson().country()) &&
        (account.hasCreditcardAttached() ||
            account.hasPrepaidcardAttached() ||
            account.hasCash());
  }

Granted, a few more and my IntelliJ will start to complain about the number of expressions in the if statement, and it's possible to clean it up a little by creating separate methods for some of the expressions. But I feel it looks fine.

So, in conclusion, just because you know something cool and shiny, it's no reason to try and use it everywhere!

It is a corrolary that in order to properly use something, you must have some knowledge or experience of when and where it's best to be used.

Thursday 16 November 2023

Adding a device to a raid with mdadm

Reordering partitions to make room

So my current hard drives are:

# lsscsi
[0:0:0:0]    disk    ATA      Samsung SSD 860  1B6Q  /dev/sda 
[4:0:0:0]    disk    ATA      WDC WD4003FZEX-0 1A01  /dev/sdb 
[5:0:0:0]    disk    ATA      WDC WD5000AAKS-0 3B01  /dev/sdc 
[5:0:1:0]    disk    ATA      ST2000DM001-1CH1 CC29  /dev/sdd 
[10:0:0:0]   disk    WD       Ext HDD 1021     2021  /dev/sde 
[11:0:0:0]   disk    WD       Ext HDD 1021     2021  /dev/sdf 

I had a lot of unused space on /dev/sdb, and thought I could rearrange the partitions and use it as an additional device in my (software) RAID.

I used Parted1, but GParted2 is also very nice. GParted can also scan my /dev/md127, which is a raid device.

Of course there's the general problem nowadays of looking what kind of MBR/GPT or whatever boot schema you use.

So:

Disk /dev/sdb: 3.64 TiB, 4000787030016 bytes, 7814037168 sectors
Disk model: WDC WD4003FZEX-0
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: D344E388-FA66-4B30-BA00-4D3B12A07B79
Device          Start        End    Sectors  Size Type
/dev/sdb1        2048       4095       2048    1M BIOS boot
/dev/sdb2        4096    1028095    1024000  500M Linux filesystem
/dev/sdb3     1028096 5273437500 5272409405  2.5T Linux filesystem
/dev/sdb4  5273438208 7420921855 2147483648    1T Linux filesystem

So it's a 4 TB hard drive, and it turns out that I only use /dev/sdb3. (The other partitions are from an old Linux install before I got a nice SDD and reinstalled Linux/Windows on that.)

So I could first rearrange it: resize /dev/sdb3 to 2T and move it to /dev/sdb1.

That worked fine using Parted. It just took some time to actually move all the data.

And then create a new /dev/sdb2 of 2T for my raid with gdisk3 (the GPT version of fdisk).

I had to look up the appropriate partition type in GPT4 for mdadm.

# gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.9

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.
Command (? for help): n
Partition number (2-128, default 2): 
First sector (34-7814037134, default = 3907006464) or {+-}size{KMGTP}: 
Last sector (3907006464-7814037134, default = 7814035455) or {+-}size{KMGTP}: 
Current type is 8300 (Linux filesystem)


Hex code or GUID (L to show codes, Enter = 8300): fd00
Changed type of partition to 'Linux RAID'

Command (? for help): p
Disk /dev/sdb: 7814037168 sectors, 3.6 TiB
Model: WDC WD4003FZEX-0
Sector size (logical/physical): 512/4096 bytes
Disk identifier (GUID): D344E388-FA66-4B30-BA00-4D3B12A07B79
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 7814037134
Partitions will be aligned on 2048-sector boundaries
Total free space is 3693 sectors (1.8 MiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048      3907006463   1.8 TiB     8300  
   2      3907006464      7814035455   1.8 TiB     FD00  Linux RAID

Adding the device

Current raid setup:

# mdadm --assemble /dev/md127 /dev/sdd1 /dev/sde1 /dev/sdf1
mdadm: /dev/md127 has been started with 3 drives.

# mdadm --detail /dev/md127
/dev/md127:
           Version : 1.2
     Creation Time : Wed Mar  6 22:16:05 2013
        Raid Level : raid1
        Array Size : 1953380160 (1862.89 GiB 2000.26 GB)
     Used Dev Size : 1953380160 (1862.89 GiB 2000.26 GB)
      Raid Devices : 3
     Total Devices : 3
       Persistence : Superblock is persistent

       Update Time : Wed Aug 16 09:08:07 2023
             State : clean 
    Active Devices : 3
   Working Devices : 3
    Failed Devices : 0
     Spare Devices : 0

Consistency Policy : resync

              Name : micemouse:0
              UUID : ed4531c4:59c132b2:a6bfc3d1:6da3b928
            Events : 7285

    Number   Major   Minor   RaidDevice State
       4       8       65        0      active sync   /dev/sde1
       5       8       81        1      active sync   /dev/sdf1
       3       8       49        2      active sync   /dev/sdd1
# cat /proc/mdstat
Personalities : [raid1] 
md127 : active raid1 sde1[4] sdd1[3] sdf1[5]
      1953380160 blocks super 1.2 [3/3] [UUU]
      
unused devices: <none>

Adding a device:

mdadm --add /dev/md127 /dev/sdb2
mdadm: added /dev/sdb2
  
md127 : active raid1 sdb2[6](S) sde1[4] sdd1[3] sdf1[5]
      1953380160 blocks super 1.2 [3/3] [UUU]
      
unused devices: <none>
 mdadm --detail /dev/md127
/dev/md127:
           Version : 1.2
     Creation Time : Wed Mar  6 22:16:05 2013
        Raid Level : raid1
        Array Size : 1953380160 (1862.89 GiB 2000.26 GB)
     Used Dev Size : 1953380160 (1862.89 GiB 2000.26 GB)
      Raid Devices : 3
     Total Devices : 4
       Persistence : Superblock is persistent

       Update Time : Sat Aug 19 16:47:58 2023
             State : clean 
    Active Devices : 3
   Working Devices : 4
    Failed Devices : 0
     Spare Devices : 1

Consistency Policy : resync

              Name : micemouse:0
              UUID : ed4531c4:59c132b2:a6bfc3d1:6da3b928
            Events : 7286

    Number   Major   Minor   RaidDevice State
       4       8       65        0      active sync   /dev/sde1
       5       8       81        1      active sync   /dev/sdf1
       3       8       49        2      active sync   /dev/sdd1

       6       8       18        -      spare   /dev/sdb2
[
root@localhost ~]# mdadm --grow /dev/md127 --raid-devices=4
raid_disks for /dev/md127 set to 4

  # mdadm --detail /dev/md127
/dev/md127:
           Version : 1.2
     Creation Time : Wed Mar  6 22:16:05 2013
        Raid Level : raid1
        Array Size : 1953380160 (1862.89 GiB 2000.26 GB)
     Used Dev Size : 1953380160 (1862.89 GiB 2000.26 GB)
      Raid Devices : 4
     Total Devices : 4
       Persistence : Superblock is persistent

       Update Time : Sat Aug 19 16:49:32 2023
             State : clean, degraded, recovering 
    Active Devices : 3
   Working Devices : 4
    Failed Devices : 0
     Spare Devices : 1

Consistency Policy : resync

    Rebuild Status : 0% complete

              Name : micemouse:0
              UUID : ed4531c4:59c132b2:a6bfc3d1:6da3b928
            Events : 7290

    Number   Major   Minor   RaidDevice State
       4       8       65        0      active sync   /dev/sde1
       5       8       81        1      active sync   /dev/sdf1
       3       8       49        2      active sync   /dev/sdd1
       6       8       18        3      spare rebuilding   /dev/sdb2

And now we wait.

# cat /proc/mdstat
Personalities : [raid1] 
md127 : active raid1 sdb2[6] sde1[4] sdd1[3] sdf1[5]
      1953380160 blocks super 1.2 [4/3] [UUU_]
      [>....................]  recovery =  0.1% (2956032/1953380160) finish=1156.0min speed=28118K/sec
      
unused devices: <none>

Ready in about 12 hours.

References

[1] Parted User’s Manual
https://www.gnu.org/software/parted/manual/parted.html
[2] GParted is a free partition editor for graphically managing your disk partitions.
https://gparted.org/
[3] gdisk(8) - Linux man page
https://linux.die.net/man/8/gdisk/
[4] Raid Wiki Kernel Org - Partition Types
https://raid.wiki.kernel.org/index.php/Partition_Types
WP Guru - How to add a drive to software RAID with mdadm
https://wpguru.co.uk/2021/01/expand-software-raid-mdadm/

Thursday 9 November 2023

The Java Playground

Apparently there's an official Java Playground on https://dev.java/.

They are working on using the Playground in your own webpages.

It is primarily created for developers to play around with the new Java, without having to install the new java.

But it's early and they have plans for it.

References

dev.java - The Java Playground
https://dev.java/playground/
dev.java
https://dev.java/

Thursday 2 November 2023

How to Change a Git Remote

I needed to change a remote, as the ip address of the remote server had changed.

$ git remote -v
origin ssh://mrbear@192.168.2.1:/home/mrbear/store (fetch)
origin ssh://mrbear@192.168.2.1:/home/mrbear/store (push)

So to change it:

git remote set-url origin ssh://mrbear@192.168.2.7:/home/mrbear/store

And it becomes:

$ git remote -v
origin ssh://mrbear@192.168.2.7:/home/mrbear/store (fetch)
origin ssh://mrbear@192.168.2.7:/home/mrbear/store (push)

References

CareerKarma - How to Change a Git Remote
https://careerkarma.com/blog/git-change-remote/