Difference between revisions of "Nodal-wikid.pl"

From Organic Design wiki
m
(Add infinite peerd loop)
Line 33: Line 33:
 
use constant LANG => 17;
 
use constant LANG => 17;
 
use constant PERL => 18;
 
use constant PERL => 18;
 
# Put here so it's local to Nodal methods
 
# - logAdd is only used until control is passed to Reduction
 
sub logAdd {
 
my $entry = shift;
 
open LOGH, '>>', "$peer.log" or die "Can't open $peer.log for writing!";
 
print LOGH localtime()." : $entry\n"; close LOGH;
 
}
 
  
 
# Create the actual data structure with its three aspects
 
# Create the actual data structure with its three aspects
Line 153: Line 145:
 
# something
 
# something
 
}
 
}
logAdd "$#synclist nodes exported.";
+
&::logAdd( "$#synclist nodes exported." );
 
}
 
}
  
Line 181: Line 173:
 
{ $2 ? $$space{$node}{$1} = $$space{$3} : push @{ $$space{$node}->list }, $$space{$1} }
 
{ $2 ? $$space{$node}{$1} = $$space{$3} : push @{ $$space{$node}->list }, $$space{$1} }
 
close NODEH
 
close NODEH
} else { logAdd "Couldn't read LIST & HASH content for: $node!" }
+
} else { &::logAdd( "Couldn't read LIST & HASH content for: $node!" ) }
  
 
# Read in SCALAR aspect
 
# Read in SCALAR aspect
Line 189: Line 181:
 
sysread FH, $$node->object, 1000000;
 
sysread FH, $$node->object, 1000000;
 
close FH;
 
close FH;
} else { logAdd "Couldn't read SCALAR content for: $node!" }
+
} else { &::logAdd( "Couldn't read SCALAR content for: $node!" ) }
  
 
}
 
}
  
logAdd "$#rootlist nodes nodes imported.";
+
&::logAdd( "$#rootlist nodes nodes imported." );
 
}
 
}
  
Line 226: Line 218:
 
push @{ $space->list }, $$space{Nodal::INIT};
 
push @{ $space->list }, $$space{Nodal::INIT};
  
sub nodalReduce {
+
# This is an infinite quanta/sec loop running in its own thread
}
+
sub peerd {
 +
while(1) {
 +
sleep(1);
 +
}
 +
}

Revision as of 22:22, 12 February 2006

  1. Licensed under LGPL: www.gnu.org/copyleft/lesser.html
  2. NodalWikid.pl - NodalHash using wiki as persistence (before moving to peerd)
  3. NOTE: peerd is extremely inefficient!
  4. Nodes should be based on binary (see ListSpace), rather than PERL's tied hashes
  5. And NodalWikid.pl is even more inefficient :-)

our $maxNodes = 1000; our %space; our $space;

  1. ----------------------------------------------------------------------------------------------------------- #
  2. NODAL CORE CLASS
  3. - Converts a standard PERL hash-table into a Distributed Computational Hash Table
  4. - This class is "hardwired" to act on %::space

package Nodal; use Scalar::Util qw( refaddr ); use Carp;

  1. Nodes needed for nodal operation

use constant OBJECT => 0; # aka ROOT use constant LIST => 1; # aka SUBJECT use constant HASH => 2; # aka CONTENT use constant SELF => 3; # aka THIS use constant HUSK => 4; use constant INIT => 6; # aka onCreate use constant MAIN => 7; use constant EXIT => 8; # aka onRemove use constant GUID => 10; use constant NAME => 11; use constant CODE => 16; use constant LANG => 17; use constant PERL => 18;

  1. Create the actual data structure with its three aspects
  2. - The internal structure is a three element array containing scalar, listref and hashref
  3. the hash aspect uses a two element array for keys which are refs because the actual
  4. hash-key can only be the address of a ref, so its stored as {ref-addr} = [ref-key,value]

sub TIEHASH { my $this = []; # Note that the internal data structure is actually an array not a hash bless $this, shift; $this->CLEAR; return $this; }

  1. Used when a NodalHash is assigned with {} or initialised with TIEHASH
  2. - clears all three aspects of the NodalHash object

sub CLEAR { my $this = shift; $$this[OBJECT] = ; $$this[LIST] = []; $$this[HASH] = {}; }

  1. Return value in passed key
  2. - if value is a ref (which it should be) then it's blessed as a NodalHash so methods are accessible
  3. - remember, keys which are refs must be treated specially to preserve the key as a reference
  4. - the special key of -i returns the nodes internal data-structure (a 3-element array)
  5. the internal structure is only meant for use by other non-TIEHASH methods of the Nodal class
  6. - onAccess happens here, but it may not be a useful concept to adopt

sub FETCH { my ( $this, $key, $val ) = @_; return $this if $key eq -i; my $k = ref $key ? refaddr $key : $key; $val = exists $$this[HASH]{$k} ? $$this[HASH]{$k}[1] : undef; $val = $$val[1] if ref $key; return ref $val ? bless $val, ref $this : $val; }

  1. Store val in key of NodalHash
  2. - If key is a ref, then store key and val together using address as key
  3. - If val is a hash, tie it to this Nodal class

sub STORE { my ( $this, $key, $val ) = @_; my $k = ref $key ? refaddr $key : $key; tie %$val, ref $this if ref $val eq 'HASH' and not tied %$val; # Get current value my $cur = exists $$this[HASH]{$k} ? $$this[HASH]{$k} : undef; $cur = $$cur[1] if ref $key; # If changing, update, queue for propagation and queue any onChange if ( $val ne $cur ) { $$this[HASH]{$k} = ref $key ? [$key, $val] : $val; # QUEUE THE CHANGE FOR SYNC HERE (general onChange may not be useful) } $val; }

  1. Nodal Reduction
  2. - An item shifts off to executes, it returns what to push back on (if anything)
  3. - If there is no code here, then execution goes within, and the same node is pushed back on
  4. Reducable items with no cod ere Processes, their presence is controlled by their INIT and EXIT processes
  5. - If there is code, but not locally executable, then build from this language's text description

sub reduce { my @list = shift->{-i}[LIST]; return unless my $node = shift @list; if ( exists $$node{CODE} ) { my $code = $$node{CODE}{ $$space{SELF}{LANG} }->object; $$node{CODE}->object = eval "sub{$code}" unless $$node{CODE}->object; if ( ref $$node{CODE}->object eq 'CODE' ) { $node = &{ $$node{CODE}->object } } else { # error: could not declare this code in local language # - we need to create an instance of this kind of error } } else { $node->reduce } push @list, $node if ref $node; }

sub DELETE { my ( $this, $key ) = @_; delete $$this[HASH]{ ref $key ? refaddr $key : $key }; }

sub EXISTS { my ( $this, $key ) = @_; exists $$this[HASH]{ ref $key ? refaddr $key : $key }; }

  1. Returns an array reference to the nodes LIST aspect

sub list { return shift->{-i}[LIST] }

  1. Returns a hash reference to the nodes HASH aspect

sub hash { return shift->{-i}[HASH] }

  1. Returns ref to lambda content
  2. - Content is returned directly if already a reference

sub object { my $val = shift->{-i}[OBJECT]; return ref $val ? $val : \$val; }

  1. Writes and flushes LIST/HASH change-buffer to local file-cache
  2. - ROOT's LIST aspect is the ordered list of all nodes
  3. the root when loaded has [] and the loaded LIST in {} and @root
  4. - actual LIST/HASH content of each node is in guid.12 file, SCALAR in <guid>
  1. OR
  2. - what if the quanta start at this peer not root
  3. - then root's LIST aspect can be @space

sub sync { my $this = shift; my @synclist = @{ $$this{SYNC}->list }; for ( @synclist ) { # something } &::logAdd( "$#synclist nodes exported." ); }

  1. Loads $::maxNodes of CONTENT/SUBJECT from local file-cache
  2. - saved from @root list

sub load { my @rootlist = @{ $space->list };

# first loop thru maxNodes of root-list and create empty hashrefs # - the new hashref is a NodalHash (because assigned to a NodalHash key) # - don't know what to do with root a:b yet open ROOTH, '<', $peer.LIST.HASH; while ( <ROOTH> =~ /^(.+?)(:(.+?))?$/ && $#rootlist < $::maxNodes ) { my $node = $$space{$1} = {}; ${ $$node{GUID}->object } = $1 unless $2; push @rootlist, $node; } close ROOTH;

# now loop thru all empty nodes and populate from their associated files for my $node ( @rootlist ) { my $guid = $$node{GUID}->object;

# Read in nodal portion (LIST and HASH aspects) if ( open NODEH, '<', $guid.LIST.HASH ) { while ( <NODEH> =~ /^(.+?)(:(.+?))?$/ ) { $2 ? $$space{$node}{$1} = $$space{$3} : push @{ $$space{$node}->list }, $$space{$1} } close NODEH } else { &::logAdd( "Couldn't read LIST & HASH content for: $node!" ) }

# Read in SCALAR aspect # - todo: only read small files here, large ones on demand if ( open NODEH, '<', $guid.OBJECT ) { binmode FH; sysread FH, $$node->object, 1000000; close FH; } else { &::logAdd( "Couldn't read SCALAR content for: $node!" ) }

}

&::logAdd( "$#rootlist nodes nodes imported." ); }

  1. ----------------------------------------------------------------------------------------------------------- #
  2. MAIN LOOP

package main;

Nodal::logAdd; Nodal::logAdd "Starting peerd as $peer:";

  1. Create global %space, tie to Nodal class
  2. - $space is a blessed ref to %space for executing the non-TIEHASH methods of %space

tie %space, 'Nodal'; $space = \%space; bless $space, 'Nodal';

  1. Load persistent content
  2. - this is not done in TIEHASH since only root should initialise the loading

$space->load;

  1. Convert $peer from name to node-ref of this peer in %space and map to SELF

$peer = $space; Nodal::logAdd 'GUID for this peer is '.$$peer{Nodal::GUID}; $$space{Nodal::SELF} = $$space{$peer};

  1. Set SELF's LANG to PERL

$$space{Nodal::SELF}{Nodal::LANG} = $$space{Nodal::PERL};

  1. Push peer's INIT onto root queue
  2. - when INIT is finished, root contains MAIN for this peer

push @{ $space->list }, $$space{Nodal::INIT};

  1. This is an infinite quanta/sec loop running in its own thread

sub peerd { while(1) { sleep(1); } }