Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Apr 16th, 2007, 11:06 PM   #1
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 403
Rep Power: 3 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
An Attempt at a DBMS

My current project which is my forum software board uses a flat file database in order to store the forum's data (user data, post data, etc.). I grew curious and starting wondering how actual databases work, and realized that the grimBase class I created is a sort of pseudo-relational database. However, what I always seem to read is that irrelevant of the database, data is stored in tables in a column and row format of some sort. I don't know how the actual implementations go, but I wanted to address a problem in my implementation. I would imagine this falls under the category of creating locks for a database. So here's the code for the grimBase class.[PHP]<?php
echo '<pre>';
$blah = new grimBase('foo.php');
$blah->generateGlyph(array(0, 1, 2, 3, 4));
print_r($blah->parseGlyph());
echo '</pre>';

class grimBase{
var $gbArtefact;
var $gbTablet;
var $gbGlyph;
var $gbArtefactExists = false;
var $gbIsTablet = false;
var $gbGlyphData = null;

function grimBase($artefactID){
if(!isset($artefactID)) trigger_error("grimBase ( string filename) &rarr; Undefined argument filename", E_USER_ERROR);
if(!is_string($artefactID)) trigger_error("grimBase ( string filename) &rarr; filename is an incorrect type", E_USER_ERROR);
if(strlen($artefactID) == 0) trigger_error("grimBase ( string filename) &rarr; filename cannot be an empty string", E_USER_ERROR);
$slashPos = strpos($artefactID, '/');
if($slashPos === 0 || $slashPos === strlen($artefactID) - 1) trigger_error("grimBase ( string filename) &rarr; filename cannot start with a / or end with a /", E_USER_ERROR);
$this->gbArtefact = $artefactID;
$this->gbArtefactExists = file_exists($this->gbArtefact);
$this->gbIsTablet = is_dir($artefactID);
$gbTemp = explode('/', $artefactID);
$dotPos = strpos(end($gbTemp), '.');
if($dotPos !== false && $dotPos !== strlen(current($gbTemp)) - 1){
$this->gbGlyph = array_pop($gbTemp);
}else{
$this->gbGlyph = '';
}
if(count($gbTemp) > 1){
$this->gbTablet = implode('/', $gbTemp);
}else{
$this->gbTablet = reset($gbTemp);
}
}

function artefact(){
return $this->gbArtefact;
}

function tablet(){
return $this->gbTablet;
}

function glyph(){
return $this->gbGlyph;
}

function artefactExists(){
return $this->gbArtefactExists;
}

function artefactCount(){
if(!$this->gbArtefactExists) return !trigger_error("int grimBase->artefactCount ( void) &rarr; Tablet does not exist", E_USER_ERROR);
return count($this->getArtefacts());
}

function getArtefacts(){
if(!$this->gbArtefactExists) return !trigger_error("array grimBase->getArtefacts ( void) &rarr; Tablet does not exist", E_USER_ERROR);
$far = array();
if($handle = opendir($this->gbTablet)){
while(false !== ($file = readdir($handle))){
if($file != "." && $file != ".."){
array_push($far, $file);
}
}
closedir($handle);
}
return $far;
}

function generateTablet(){
if(file_exists($this->gbTablet)) return true;
if(fluctuate($this->gbTablet, 0777)){
$this->gbArtefactExists = true;
}
return $this->gbArtefactExists;
}

function generateGlyph($glyphData){
if(!isset($glyphData)) return !trigger_error("bool grimBase->generateGlyph ( array &array) &rarr; Undefined argument &array", E_USER_ERROR);
if(!is_array($glyphData)) return !trigger_error("bool grimBase->generateGlyph ( array &array) &rarr; &array is an incorrect type", E_USER_ERROR);
if(count($glyphData) == 0) return !trigger_error("bool grimBase->generateGlyph ( array &array) &rarr; &array is empty", E_USER_ERROR);
$this->gbGlyphData = $glyphData;
$fout = '<?php /*' . chr(30);
foreach($glyphData as $glyphKey => $glyphValue){
$fout .= $glyphKey;
$fout .= ' = ';
$fout .= serialize($glyphValue);
$fout .= chr(30);
}
$fout .= '*/ ?>';
if(fluctuate($this->gbArtefact, 'w', $fout, 0777)){
$this->gbArtefactExists = true;
$this->gbIsTablet = false;
$this->gbGlyphData = $glyphData;
return true;
}else{
$this->gbArtefactExists = false;
$this->gbGlyphData = null;
return false;
}
}

function scanGlyph($glyphID){
if(!$this->gbArtefactExists) return !trigger_error("mixed grimBase->scanGlyph ( string arrayKey) &rarr; Glyph does not exist", E_USER_ERROR);
if($this->gbIsTablet) return !trigger_error("mixed grimBase->scanGlyph ( string arrayKey) &rarr; Cannot parse a tablet", E_USER_ERROR);
if(!isset($this->gbGlyphData)){
$this->gbGlyphData = $this->parseGlyph();
}
return $this->gbGlyphData[$glyphID];
}

function parseGlyph(){
if(!$this->gbArtefactExists) return !trigger_error("array grimBase->parseGlyph ( void) &rarr; Glyph does not exist", E_USER_ERROR);
if($this->gbIsTablet) return !trigger_error("array grimBase->parseGlyph ( void) &rarr; Cannot parse a tablet", E_USER_ERROR);
$parseContent = file_get_contents($this->gbArtefact);
if(false === $parseContent) return !trigger_error("array grimBase->parseGlyph ( void) &rarr; Unable to retrieve glyph contents", E_USER_ERROR);
$contentParser = explode(chr(30), $parseContent);
$parseContent = array();
array_shift($contentParser);
array_pop($contentParser);
reset($contentParser);
foreach($contentParser as $contentValue){
$ePos = strpos($contentValue, '=');
$parseKey = trim(substr($contentValue, 0, $ePos - 1));
$parseValue = unserialize(substr($contentValue, $ePos + 2));
$parseContent[$parseKey] = $parseValue;
}
$this->gbGlyphData = $parseContent;
return $parseContent;
}
}

function fluctuate(){
$args = func_get_args();
switch(func_num_args()){
case 1:
if(!is_string($args[0])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; <em>filename</em> is not a string", E_USER_ERROR);
if(is_file($args[0])){
if(unlink($args[0])) return true;
else return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Unable to delete file", E_USER_WARNING);
}elseif(is_dir($args[0])){
if(rmdir($args[0])) return true;
else return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Unable to delete folder", E_USER_WARNING);
}else return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Nonexistent file/directory cannot be deleted", E_USER_NOTICE);
case 2:
if(!is_string($args[0])) return !trigger_error("bool fluctuate ( string dirname [, int mode]) &rarr; <em>filename</em> is not a string", E_USER_ERROR);
if(!is_int($args[1])) return !trigger_error("bool fluctuate ( string dirname [, int mode]) &rarr; <em>mode</em> is not an int", E_USER_ERROR);
if(mkdir($args[0], $args[1])){
return true;
}else{
return !trigger_error("bool fluctuate ( string dirname [, int mode]) &rarr; Unable to create directory", E_USER_ERROR);
}
case 4:
if(!is_string($args[0])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; <em>filename</em> is not a string", E_USER_ERROR);
if(!is_string($args[1]) || strlen($args[1]) !== 1) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; <em>mode</em> is not a character", E_USER_ERROR);
if(!is_int($args[3])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; <em>mode</em> is not an int", E_USER_ERROR);
$args[1] = strtolower($args[1]);
$ffd = null;
switch($args[1]){
case 'a':
if(!file_exists($args[0])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Cannot append to nonexistent file", E_USER_WARNING);
if(!is_writeable($args[0])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; File is not writeable", E_USER_WARNING);
if(false === ($ffd = fopen($args[0], "a"))) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Unable to open file", E_USER_WARNING);
break;
case 'w':
if(false === ($ffd = fopen($args[0], "w"))) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Unable to open file", E_USER_WARNING);
if(!file_exists($args[0])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Cannot write to nonexistent file", E_USER_WARNING);
if(!is_writeable($args[0])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; File is not writeable", E_USER_WARNING);
break;
default:
return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Illegal mode specified", E_USER_ERROR);
}
if(stream_set_write_buffer($ffd, 0) !== -1) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Unable to buffer stream", E_USER_WARNING);
if(fwrite($ffd, $args[2]) === false) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Unable to write to file", E_USER_WARNING);
if(!fclose($ffd)) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Unable to close file", E_USER_WARNING);
if(!chmod($args[0], $args[3])) return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Unable to change file permissions", E_USER_WARNING);
return true;
default:
return !trigger_error("bool fluctuate ( string filename [, string mode [, string string [, int mode]]]) &rarr; Incorrect quantity of arguments supplied", E_USER_ERROR);
}
}
?>[/PHP]Now to compare actual database tables to my own there's 3 things to know about the grimBase class. It is composed of what I call Artefacts, Tablets, and Glyphs. Tablets and Glyphs are both Artefacts. On your local computer Tablets are the equivalent of folders/directories and Glyphs are ascii text files. So for instance when I want to create a database table (what I call a Tablet) I would code something like
$foo = new grimBase('foo');
$foo->generateTablet();
Now if I wanted to add an row to the table I would code something like the following
$foo = new grimBase('foo/0.php');
$foo->generateGlyph(array(0, 1, 2, 3, 4));
And that adds a row to the table (the row itself is what I call a Glyph). Therefore a database table with various entries in it in my grimBase is equivalent to a Tablet with various Glyphs in it. Physically this is a folder with various files in it. Now as far as writing to the same Glyph at the exact same time that can't happen because of the set_stream_write_buffer function. However, let's say two users want to reply to a topic in the forum at the same time, the forum automatically creates a Glyph reference to the next needed file, so now two users are referencing the same Glyph record. So now an overwrite of one of the two user's posts can occur. Whoever submits their post last I would imagine. There's an intermediate step where a final check is performed to ensure that that post hasn't already been created, but I imagine there's still a possibility that due to timing the post may still get overriden. So my question is how can I possibly create a lock to prevent that from happening? Or am I looking at this database thing all wrong in terms of the implementation? Should I rather than using individual files use one file and then just add rows? I realize this may be more complicated than what I think, and I have been reading on the subject and book on DBMS where the author stipulates these locks are necessary and I understand why, it's just it's a conceptual book and doesn't actually deal with the physical aspect of programming it.
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis

Last edited by grimpirate; Apr 16th, 2007 at 11:19 PM.
grimpirate is offline   Reply With Quote
Old Apr 16th, 2007, 11:26 PM   #2
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 6,453
Rep Power: 10 DaWei is on a distinguished road
There's nothing wrong with experimenting around, in the dark, in an attempt to invent databases. I would suggest that you would be well ahead of the game if you learned how current databases work and experimented around, in the light, in an attempt to improve on them. Just personal opinion.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code.
Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers
DaWei is offline   Reply With Quote
Old Apr 16th, 2007, 11:59 PM   #3
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 403
Rep Power: 3 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
I agree DaWei, I'm not trying to reinvent the wheel or anything. I'm reading the book Database Management Systems 2nd Ed. from McGraw Hill. It talks about a great deal of things that I can't really seem to find much info about online. Usually all I manage to end up googling is someone explaining SQL or how SQL works to get stuff done, how the tables look, etc. It's all very kind of separated from the code that creates the database. There's sqllite, but that's written in C and my grasp of C is limited. Furthermore, I'm pretty weak at reading other's code. I'm not actually trying to improve databases. It's just that I use free webservers so it would be nice to have one that's free. There's one that I found which is txtSQL which I have yet to look into further, but it's always very difficult to study someone else's code if it isn't explained entirely.
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Old Apr 17th, 2007, 4:52 AM   #4
kruptof
Professional Programmer
 
kruptof's Avatar
 
Join Date: May 2006
Location: UK - London
Posts: 329
Rep Power: 3 kruptof is on a distinguished road
What you need to do is find out the functions of a DBMS, for example:
Store, retrieve and update data
Transaction Services
Data-independence
Data integrity service
Security service
Concurrency control service
Data Communication Service
Recovery and Backup services

Also I think there is something called the ANSI-SPARC Three Layer Model that you can follow to help with the design and hopefully the implementation of your DBMS
__________________
Quote:
When I was young it seemed that life was so wonderful,a miracle, oh it was beautiful, magical.
Now watch what you say or they'll be calling you a radical,a liberal, oh fanatical, criminal. Oh won't you sign up your name,we'd like to feel you're acceptable, respectable, oh presentable, a vegetable
kruptof is offline   Reply With Quote
Old Apr 17th, 2007, 7:56 AM   #5
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 6,453
Rep Power: 10 DaWei is on a distinguished road
If you have a machine at home, I'd recommend you put an AMP package on it and play with that. Then you'll know how to use a DB if/when you have a host that supports it.

Writing a DB has two aspects. One is the functionality. You can learn to write that in any language, but the end result will likely be missing the other aspect: performance. Performance is attained by writing code that is very system specific, close to the machine.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code.
Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers
DaWei is offline   Reply With Quote
Old Apr 17th, 2007, 8:55 AM   #6
Infinite Recursion
Programming Guru
 
Infinite Recursion's Avatar
 
Join Date: Jul 2004
Location: United States
Posts: 3,466
Rep Power: 8 Infinite Recursion is on a distinguished road
Send a message via MSN to Infinite Recursion Send a message via Yahoo to Infinite Recursion
Quote:
It's just that I use free webservers so it would be nice to have one that's free.
MySQL is free. http://www.mysql.com/

Kudos on your effort. Makes me want to write a web application in PHP now.
__________________
http://jasonpowers.net

"There are a thousand hacking at the branches of evil to one who is striking at the root."
Infinite Recursion is offline   Reply With Quote
Old Apr 17th, 2007, 12:38 PM   #7
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 403
Rep Power: 3 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
@kruptof: Hmm... browsed around for ANSI - SPARC but I mostly find cryptic definitions. All those concepts you mention are addressed in the book I'm reading, along with ACID and many others.

@DaWei: When I search for AMP package on Google all I get are like actual guitar amps lol, sorry I don't know what the acronym stands for. I've already worked with databases and understand how to use the SQL language and such. However, that's very separated from the actual physical things going on in a database,and of course performance is undoubtedly a crucial feature of a database. However, due to my free webhost constraint performance is secondary. I would venture to hypothesize that perhaps using the PHP filesystem functions and the like might be quicker than actually logging into the database and polling it over and over, at least online that is.

@Infinite Recursion: lol yeah I know that MySQL is free and open source, that isn't what I mean though. Your host still has to grant you database access to use MySQL, and a lot of free webhosts don't. Happy I could get you motivated ^_^ How about a mod for GrimBB? SHAMELESS PLUG! lol

@anyone still reading: I did find this other pretty impressive flat file database http://gladius.sourceforge.net/. That's pretty much what I'm trying to create. However, looking at their source code gives me a headache *_* lol Obviously those people know what they're doing as I ignorantly assume good code gives me a headache.
Regarding the problem that I was stating earlier I think I may have come up with a solution. When a user decides to make a post I should immediately create a Glyph which indicates that someone is accessing the Tablet in order to create a post. Perhaps this Glyph could contain a queue of sorts, so as to process each user's post systematically. I assume that if the same thing where to happen here on PFO the thread wouldn't update dynamically if a post was made right now while I'm typing this one.
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Old Apr 17th, 2007, 1:00 PM   #8
kruptof
Professional Programmer
 
kruptof's Avatar
 
Join Date: May 2006
Location: UK - London
Posts: 329
Rep Power: 3 kruptof is on a distinguished road
here is what i think Dawei meant http://www.wampserver.com/en/, good for practising and testing your project on.
__________________
Quote:
When I was young it seemed that life was so wonderful,a miracle, oh it was beautiful, magical.
Now watch what you say or they'll be calling you a radical,a liberal, oh fanatical, criminal. Oh won't you sign up your name,we'd like to feel you're acceptable, respectable, oh presentable, a vegetable
kruptof is offline   Reply With Quote
Old Apr 17th, 2007, 1:01 PM   #9
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 6,453
Rep Power: 10 DaWei is on a distinguished road
AMP is Apache/MySql/PHP. It's a very easy thing to implement. You can also find binary packages the do the entire installation, but I don't like them as well.

This kind of setup allows you to play on your home machine, regardless of what your host provides. You can also add things like Perl to the mix.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code.
Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers
DaWei is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Connection attempt zorin Coder's Corner Lounge 11 Sep 15th, 2005 1:55 PM
Add DBMS section codetaino Community Announcements and Feedback 4 Jan 15th, 2005 1:25 PM




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 1:39 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC