-- $Id: namenode.sql 488 2011-10-25 21:29:23Z gerd $

-- Database definition for the namenode database
-- This is for PostgreSQL 8.2 or better

CREATE TABLE datastore (
	id	 INTEGER NOT NULL,      -- The id in this database
	identity VARCHAR(64) NOT NULL,  -- The external id
	size     BIGINT NOT NULL,       -- number of blocks
	enabled  BOOLEAN NOT NULL,
	PRIMARY KEY (id),
	UNIQUE(identity)
) WITHOUT OIDS;

CREATE TABLE blockalloc (
	datastore  INTEGER REFERENCES datastore(id) ON DELETE CASCADE NOT NULL ,
	-- the datastore where the blocks are stored

	blkidx	  BIGINT NOT NULL,
	-- the first data block this record is about. Normally, this
        -- record is about 1024 blocks, i.e. the last block is
        -- blkidx+1023. However, if this exceeds the number of blocks
        -- on this node this record is about fewer blocks

	blkmap	  BIT VARYING(1024) NOT NULL,
	-- for every block this bit string says whether it is used (1)
        -- or free (0)
	
	blkcnt    INTEGER NOT NULL,
	-- the number of used blocks in blkmap

	PRIMARY KEY (datastore, blkidx)
) WITHOUT OIDS;

-- Look up whether [block] is free:
-- SELECT substring(blkmap FROM block & 1023 FOR 1) :: integer
-- WHERE datastore=... AND blkidx=block & (~1023)


--CREATE INDEX blockalloc_cnt ON blockalloc(datastore, blkcnt);
-- This index is useful to find range of blocks

CREATE TABLE inode (
	id	  BIGINT NOT NULL,        -- inode ID
	ftype     CHARACTER(1) NOT NULL,
	username  VARCHAR(64) NOT NULL,
	groupname VARCHAR(64) NOT NULL,
	mode	  INTEGER NOT NULL,
	eof	  BIGINT NOT NULL,
	mtime1    BIGINT NOT NULL,   -- seconds
	mtime2    INTEGER NOT NULL,  -- nanoseconds
	ctime1    BIGINT NOT NULL,   -- seconds
	ctime2    INTEGER NOT NULL,  -- nanoseconds
	blimit	  BIGINT NOT NULL,
	repfactor INTEGER NOT NULL,
	field1    TEXT NOT NULL,
	seqno     BIGINT NOT NULL,
	crverf    BIGINT NOT NULL,
	anonymous BIGINT,            -- set to id if applicable
	PRIMARY KEY(id)
) WITHOUT OIDS;

CREATE INDEX inode_anonymous ON inode(anonymous) WHERE anonymous IS NOT NULL;
-- index only the rows where anonymous is not NULL

CREATE TABLE inodeblocks (
	inode     BIGINT REFERENCES inode(id) ON DELETE CASCADE NOT NULL,
	blkidxmin BIGINT NOT NULL,
	blkidxmax BIGINT NOT NULL,
	datastore  INTEGER REFERENCES datastore(id) ON DELETE CASCADE NOT NULL,
	block     BIGINT NOT NULL
	-- The index [k] is stored in [block+k-blkidxmin] of [datastore],
	-- for [blkidxmin <= k <= blkidxmax]
) WITHOUT OIDS;

CREATE INDEX inodeblocks1 ON inodeblocks(inode,blkidxmin,datastore);
CREATE INDEX inodeblocks2 ON inodeblocks(inode,blkidxmax,datastore);

-- allocinfo stores only selected blocks of the inode. Usually only
-- the last allocated block of each datastore is stored. This helps when
-- extending the file. Allocinfo is not updated when blocks are deallocated.
-- The information may be outdated.

CREATE TABLE allocinfo (
        inode     BIGINT REFERENCES inode(id) ON DELETE CASCADE NOT NULL,
        blkidx    BIGINT NOT NULL,
	datastore INTEGER REFERENCES datastore(id) ON DELETE CASCADE NOT NULL,
	block     BIGINT NOT NULL
	-- Stores the [block] for [blkidx].
) WITHOUT OIDS;

CREATE INDEX allocinfo_inode ON allocinfo(inode);

CREATE TABLE checksums (
        inode     BIGINT REFERENCES inode(id) ON DELETE CASCADE NOT NULL,
	blkidx    BIGINT NOT NULL,
	cksum     VARCHAR(255),
	PRIMARY KEY(inode, blkidx)
) WITHOUT OIDS;

CREATE TABLE names (
       inode_d    BIGINT REFERENCES inode(id) NOT NULL,
       name       TEXT NOT NULL,
       inode      BIGINT REFERENCES inode(id) NOT NULL, -- no cascade!
       PRIMARY KEY (inode_d, name)
) WITHOUT OIDS;
-- inode_d: the containing directory
-- name: the file in the directory
-- inode: the inode of the file

CREATE INDEX names_inode_d ON names(inode_d);
-- for listing directories

CREATE INDEX names_inode ON names(inode);
-- for reverse lookups

CREATE TABLE revision (
	revstr	  VARCHAR(64) NOT NULL,
	committer INTEGER NOT NULL,
	PRIMARY KEY(committer)
) WITHOUT OIDS;
-- All committers (parallelly running commit threads) put the ID of
-- the last commit into this table (as revstr).
--
-- At startup we have to check whether all nodes have the same state.
-- For simplicity we only take the maximum revstr found in the revision
-- table.


CREATE TABLE admin_table (
       key        VARCHAR(64) NOT NULL,
       contents   TEXT NOT NULL,
       
       PRIMARY KEY(key)
) WITHOUT OIDS;


INSERT INTO revision (revstr, committer) 
VALUES ('00000000000.000000000-0102030405060708090a0b0c0d0e0f', 0);

-- insert "/"
INSERT INTO inode (id,ftype,username,groupname,mode,eof,mtime1,mtime2,
       	    	   ctime1,ctime2,blimit,repfactor,field1,seqno,crverf)
VALUES (1,'d','root','root',1023,0,0,0,0,0,0,1,'',0,0);

-- insert "passwd" and "group"
INSERT INTO admin_table(key,contents) VALUES ('passwd', '');
INSERT INTO admin_table(key,contents) VALUES ('group', '');

--INSERT INTO names (inode_d, name,inode)
--VALUES (1, '/', 1);
