Hacking just for Fun: Raid5 in Java

I was just curious how easy it might be to write a RAID5 compatible Outputstream in Java? Just a few Lines. For sure it is not the most elegante solution. Especially if you see the nice possibility to integrate one Outputstream within another… so maybe two Raid5s into one Raid0 Stream? (would be RAID50) then. Reading is missing ;-).

/**
 * Raid5Stream
 * 31.03.2012
 * @author Philipp Haussleiter
 *
 */
package de.javastream.jraid;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Raid5Stream extends OutputStream {

    public final static int PARITY_MARKER = 1;
    public final static int DATA_MARKER = 0;
    private File disks[];
    private FileOutputStream streams[];
    private int mode = 0;
    private final static int MAX_MODE = 2;
    private int[] buffer = new int[2];

    public Raid5Stream(File disks[]) throws IOException {
        super();
        if (disks.length != 3) {
            throw new RuntimeException("we need a disk count of x times 3");
        }
        int i = 0;
        this.disks = new File[disks.length];
        this.streams = new FileOutputStream[disks.length];
        for (File f : disks) {
            if (!f.exists() && !f.createNewFile()) {
                throw new RuntimeException(f.getAbsolutePath() + " does not exists and cannot be created!");
            } else {
                System.out.println("using " + f.getAbsolutePath() + "\n");
                this.disks[i] = f;
                this.streams[i] = new FileOutputStream(f);
            }
            i++;
        }
        writerMarker();
    }

    private void writerMarker() throws IOException {
        for (int i = 0; i < this.streams.length; i++) {
            if (i % 3 == 0) {
                this.streams[i].write(PARITY_MARKER);
            } else {
                this.streams[i].write(DATA_MARKER);
            }
        }
    }

    @Override
    public void write(int i) throws IOException {
        switch (mode) {
            case MAX_MODE:
                this.streams[mode].write(buffer[0] ^ buffer[1]);
                mode = 0;
            default:
                this.buffer[mode] = i;
                this.streams[mode].write(i);
                mode++;
        }
    }
}

Using it is easy as:

...
public class App {

    public static void main(String[] args) throws IOException {
        File raid5_disk1 = new File("raid5.disk1");
        File raid5_disk2 = new File("raid5.disk2");
        File raid5_disk3 = new File("raid5.disk3");
        long count = 0;
        Raid5Stream raid5Stream = new Raid5Stream(new File[]{raid5_disk1, raid5_disk2, raid5_disk3});
        FileInputStream in = new FileInputStream("/dev/random");
        BufferedInputStream bis = new BufferedInputStream(in);
        BufferedOutputStream raid5bos = new BufferedOutputStream(raid5Stream);
        while(count < 1024*1024*2){
            raid5bos.write(bis.read());
            count++;
        }
        raid5bos.close();
        bis.close();
    }
}

Good sources for more reading are the Wikipedia Articles about RAID and XOR.

Leave a Reply