distCVS: A Distributed Peer-to-Peer Versioning File Storage System Andrew Logan

advertisement
distCVS: A Distributed
Peer-to-Peer Versioning File
Storage System
Andrew Logan
May 13, 2005
Advised by:
Professor Robert Signorile
Professor Elizabeth Borowsky
Thanks to:
My family, for always encouraging me to follow my interests.
My thesis advisors, for first suggesting this problem and then
devoting a year of their time to guiding me towards a solution.
All of the other faculty and staff members at BC who donated
their time, energy and resources to this project.
And last but not least, my fellow Senior CS Thesis authors,
without whom the Unix lab would not have been nearly as much
fun at 2 am.
Contents
1 Abstract
1
2 Introduction
2
3 System Overview
9
4 Implementation
10
5 Testing
15
6 Conclusions and Future Work
18
7 Appendix A: distCVS Source Listings
8 Appendix B: Test Scripts
9 Appendix C: Bibliography
i
xxxv
lii
1
Abstract
The current layout of resources on the internet suffers from the fact that
there is generally a single point of failure for data access. Peer-to-peer applications promise to change this by distributing resources, and therefore
network routes and load, across the network itself. The problem is that
the development and testing of such a system is often a hard and tedious
chore, especially since the technology is still rapidly evolving. In this paper, I present distCVS, a peer-to-peer system for the storage of versioned
data. distCVS is unique because it is an application built by using the Bamboo peer-to-peer networking framework to pass messages for an unmodified
version of the CVS source control system. The development of this type
of peer-to-peer system allows the designer to not only rapidly assemble a
working system, it also allows him or her to take advantage of any future
improvements that may be made to either Bamboo or CVS.
1
2
Introduction
The basic layout of the internet has changed very little since its inception
in the late 1960’s. In essence, the resources of the internet are laid out in a
star topology. Client computers spread across the internet access resources
contained on a central server. The advantages of this type of system, and
part of the reason that it has been so long-lived, is that it is very easy to
find files and resources in this type of layout. Every client knows that the
resources they want to access are stored on one central server, and since the
server’s location in the network changes infrequently, clients know how to
find it. In fact, there is generally a delay ranging from several hours to as
long as one or two days when a server moves its network address until the
clients are able to find it again.
There are drawbacks to laying out a network in a star topology, though,
and these drawbacks stem from the fact that data eventually has to pass
through the central server. The network does not scale well, and there is a
single point of failure. Since once computer has to process all of the requests
coming through the network, either it or its link to the rest of the world can
easily become overwhelmed by the amount of data it has to process. If this
server goes off of the network because of this overload, some other failure, or
even routine maintenance, then none of the clients can access the resources
stored on it until it is brought back online.
Despite these problems, high-traffic sites do exist on the internet. They
2
Figure 1: An 8 node network laid out in a star topology.
tend to work around these problems by having their resources served by
networks of machines that are capable of handling the enormous traffic loads
that they experience. A more elegant solution is required, however, since this
method does not address the root causes of the scalability problems.
Over the last few years, much work has been put in to researching and
developing peer-to-peer networks,[6, 3, 4, 8, 2, 7] which suddenly became
popular in 1999 with the release and success of the Napster file sharing program. Peer-to-peer systems promise truly decentralized networks, but there
are still many problems that have not yet been solved.
The simplest form of a peer-to-peer network would connect every com-
3
puter on a network to every other one on the network. Although this scheme
does provide complete connectivity, it is not practical for several reasons.
First, there is a limit to how many network connections a computer can have
active at one time, which places a relatively small upper bound on the maximum size of the network.1 This topology was attempted with the first version
of the Gnutella peer-to-peer network, and the designers of that system soon
discovered that the information that needs to be shared to index the data on
this network imposed an enormous amount of networking overhead, which
severely limited the amount of bandwidth that could be used for sharing
data.
The popularity of Napster was partly due to the fact that it solved the
indexing problem by using a central server to keep track of the resources
available on the network.2 Although this is a clever solution to the indexing
problem, the addition of a central server makes this system not truly peer-topeer. Therefore, this network still has some of the scalability and reliability
problems that star networks do. This napster topology is better than a star
topology because the resources have been moved to the computers on the
network, relieving much of the strain on the central server. However, nodes
will not be able to locate anything on the network if the indexing server goes
1
Valid TCP/IP port numbers are in the range 1-65535. Assuming that all ports could
be used for a peer-to-peer network and that there were no conflicts in assigning port
numbers, the network would be limited to 65535 computers at any given time. Although
this number is more than sufficient for some applications, it is several orders of magnitude
lower than estimated 43 million US households with internet access.[9] Clearly, something
else has to be done to create a global peer-to-peer system.
2
See Figure 3
4
Figure 2: An 8 peer network laid out in a simplistic peer-to-peer topology.
offline, and it may still be possible to overwhelm it with location requests.
The most recent innovation in peer-to-peer networks is the use of distributed hash tables (DHT’s). DHT’s organize computers and resources on a
network in such a way that an index server is not needed. In the Bamboo[5]
implementation of this idea, each node assigns itself a random id number
based upon the port number and ip address it has when it joins the Bamboo
network.3 Each piece of data is also assigned an id number in the same range
as the ones assigned to the nodes, and then the numerically closest node in
the network to the id number assigned to a specific piece of data becomes its
3
See Figure 4
5
Figure 3: An 8 node network laid out in the topology used by the original
Napster network.
primary owner, and is responsible for maintaining current copies of this piece
of data on four nodes: the two closest nodes with greater id numbers, and
the two closest nodes with lower id numbers.4 Using random ID numbers for
the nodes helps to ensure that nodes are not on nearby subnets, which helps
prevent data from being lost if an entire subnet goes down. As nodes join
and leave the network, data is moved around to ensure that these conditions
are still met.
The Concurrent Versions System (CVS)[1] is a typical application that
4
MAX INT is assumed to be one less than MIN INT and vice versa, which causes a graph
of the network to be circular.
6
Figure 4: An 8 node network laid out in the topology used by the Bamboo
network. Numbers represent node id’s.
uses a star network topology to distribute data. A group of programmers
who are potentially dispersed across the globe will log in to a central CVS
server to retrieve and update changes to a shared codebase. The purpose
of my thesis experiment was to see if this type of system could become a
peer-to-peer system by combining it with a modular networks infrastructure,
such as Bamboo. CVS was chosen as the test program for this experiment
because, to the best of our knowledge, no such system already exists. CVS
is also easy to work with, since it stores its file repositories in a way that is
7
easily recreated. Finally, since Bamboo and CVS are both freely available
on the internet as open-source projects, they are uniquely suited to this sort
of experimentation.
8
3
System Overview
The distCVS system allows users to put, get and update files in a peer-
to-peer network, and handles all versioning and concurrency enforcement in
the background. The typical user of the system would provide it with the
name of a project and a file that he or she wanted to work on, make changes
to it, and then resubmit it into the network. If another user had submitted
changes while this copy was being worked on, the system will notify the user
that his or her file is out of date and needs to be updated before the changes
will be accepted.
Each node in a distCVS network needs to run both the Bamboo software
and the CVS software. This is done because Bamboo provides the network
system that passes data to and from copies of CVS. Bamboo also manages
a per-node database which stores copies of the cumulative version files that
are produced by CVS. These files are the main pieces of data tracked by the
network, and may be passed from node to node as the composition of the
network changes. Finally, each node also requires a copy of CVS since all
data retrieval and update operations must be done on the primary owner to
ensure that the newest copy of the data is used as a reference. Due to these
requirements, the system currently only runs on the Linux operating system,
although it should be possible to port the components to other platforms.
9
4
Implementation
Each Bamboo node is a collection of smaller components, called stages,
that provide specific functionality to that node. For example, there are stages
that store data, route messages, and handle network connections. This modular structure therefore allowed me to extend the functionality of Bamboo by
writing a stage that interacted with CVS. This stage, named DistCVSStage,
sends and receives messages, places and retrieves data in the Bamboo network, and interacts with CVS primarily through the help of two perl scripts.
This method was chosen because Perl is better suited for interaction with
command-line resources than Java is, and therefore allows for cleaner code
when automating tasks such as creating directories and moving files.
There are three main tasks that can be performed on a distCVS network:
put, get and update. When a user requests that a file be put into storage
in the network, his or her local copy of DistCVSStage reads the target file
off of local storage, calculates its id number (GUID) and generates a BambooRouteInit message carrying a PutCVSReqPayload object. This message
is routed by Bamboo to the primary owner for this piece of data, where it
is received by the copy of DistCVSStage running on that node. This copy
requests the current copy of the CVS version file from its local database by
sending a GetByGuidReq message to the StorageManager stage running on
the primary owner, which sends back a GetByGuidResp message containing
the data. Since the version of Bamboo this project is based on does not
10
Figure 5: An illustration of the distCVS file submission process.
implement deletion of old resources, extra steps need to be taken to iterate through every file referenced by a given GUID, to ensure that the most
recently stored copy is retrieved from the primary owner’s database. If no
matching data is found, then the system assumes that the submitted data is
being added for the first time. Otherwise, it is treated as an update.
The retrieved version data (if it exists) is written to disk, along with the
new file which was sent over the network. DistCVSStage then invokes the
submithelper.pl perl script, which reconstructs a repository with version information and then invokes CVS, monitoring it for errors. If an error does
occur, such as an attempted update from an obsolete version, then the error
message is passed back up to DistCVSStage, which sends a message back
across the network to notify the user. Otherwise, submithelper.pl copies the
11
new version data from the CVS repository and indicates that the process
completed successfully. DistCVSStage then retrieves this file from local storage and places it into the Bamboo network by passing a PutOrRemoveReq
message to the DataManager stage running on the primary owner. The result of this operation is passed back to DistCVSStage in a PutOrRemoveResp
message, which is used to indicate either success or failure in the PutCVSRespPayload that is wrapped in a BambooRouteInit message and sent back
to the requesting user’s copy of DistCVStage. The requesting user’s copy of
DistCVSStage then displays this message to the user, which tells him or her
whether the operation succeeded or failed.
It should be noted that the file on to the requesting user’s node is never
altered during this process, so a failure to store the data will not result
in any data loss. Also, since Bamboo is event-driven and all of its events
are stored in a queue based on the order in which they arrived, it will not
attempt to apply two updates to a file at the same time, which helps to
ensure concurrency.
File retrieval works very similarly. When a user requests a file, a BambooRouteInit message containing a GetCVSReqPayload message is sent across
the network to a primary owner. To prevent old data from being returned, a
newly-joined node will delay the processing of this request for some reasonable amount of time5 to ensure that it has the most recent copies of all of
the data it needs. Since there is no central control in a peer-to-peer network,
5
This was on the order of about 30 seconds during our tests.
12
there is no way to ensure that any given node has a globally correct piece
of data. Therefore, we were forced to assume that the correct version would
quickly propagate through the network.
Figure 6: An illustration of the distCVS file retrieval process
Once this initial delay has passed, the primary owner’s copy of DistCVSStage
queries StorageManager for the highest version of the target file stored in the
local database. If no data is found that matches the requested file’s id number, a message is sent back to the requesting node informing the user that
the file was not found. However, if it is found then this retrieved version
data is written to local storage. DistCVSStage then invokes the reconstructhelper.pl perl script, which in turn creates a fake CVS repository and invokes
CVS in such a way that it reconstructs a copy of the highest version of the
data encoded within the file retrieved from the database. The DistCVSStage
13
is alerted if this process fails, and sends a message across the network to
inform the user what the problem is. Otherwise, DistCVSStage reads the
reconstructed file from local storage, packages it and a version number into
a GetCVSRespPayload object which is wrapped in a BambooRouteInit message and sent back across the network to the requesting user’s computer. The
id number of the node that made the original request is checked by the node
that receives this packet, and it is discarded if they do not match. This is
to prevent against users receiving data that they did not request if the node
that made the request dropped from the network while the file was being reconstructed. If the GUID numbers match, however, then the reconstructed
file and a file containing its version number are written to local storage and
the user can then edit the file in any way he or she desires.
14
5
Testing
Our tests sought to answer several questions about the behavior of DistCVS.
Specifically, we wanted to see how stable the system was under a high rate
of file requests, or a high rate of nodes joining and dropping from the network. We also wanted to ensure that the correct data was always created
or returned, even when two updates happened at once, or updates were attempted from outdated version. Finally, we wanted to see what would happen in the extreme case where the entire network disappeared and then came
back online. In short, the system performed well under all of the conditions
that it was tested under.
distCVS was tested on a collection of ten Intel Pentium 4 workstations
running Red Hat Linux release 9.6 The tests were automated using a series of
perl scripts that prepared a unique directory for each node to run it, provided
copies of all of the necessary files, created configuration files and monitored
the data stored on each node for correctness. The DistCVSStage also has a
test mode which will automatically create file requests, output the response
to local storage, and repeat the process after a random interval of time has
passed. DistCVSStage can also handle not sending any more requests after a
specified time period has elapsed, which was used to flush pending messages
out of the network before the nodes were shut down. Similarly, no requests
are sent until the entire network is running, to avoid skewing the results data.
6
kernel version: 2.4.20
15
In order to ensure that nodes received the correct copy of the data from
the network, a master copy was kept on a file system shared by all of
the test machines. Whenever a response was returned, it was compared
against this master copy using the Linux diff utility. If the files were identical, a GOOD VERSION response was recorded in the node’s log. Otherwise, a
BAD VERSION was recorded if they differed, and a NOT FOUND recorded if the
data could not be retrieved from the network. Once the experiment run is
complete these log files can be parsed to compile statistics for the experiment
run.
The following tables contain the results from the experiments we ran,
along with the conditions that they were run under. A typical experiment
took around an hour to run, and consisted of a warmup period, twenty minutes of requests, the random removal of 20% of the nodes in the network,
another twenty minutes of requests, the re-insertion of the removed nodes,
a final twenty minutes of requests, and then a cooldown period where the
requests are flushed from the network.
These results illustrates the fact that even under very adverse conditions,
the network retains the ability to return either good data or a not found
warning. It very rarely returns a bad version to a user. Even this bad
version is likely to be caught when the user submits his or her changes since
a newer version will always propagate through the network if it exits.
16
number of nodes
100
200
300
total requests
2531
4995
6874
%good %bad
0.89
0
0.97
0
0.98
0
%not found %unanswered
0.11
0
0.03
0
0.02
0.01
Table 1: 12-15 minute request interval, no updates
number of nodes
100
200
300
total requests
11698
9660
%good %bad
0.82
0
0.97
0
%not found %unanswered
0.18
0
.02
0.01
Table 2: 0-30 second request interval, no updates
number of nodes
100
200
300
total requests
1684
7732
%good %bad
0.97
0
0.96
0
%not found %unanswered
0.02
0
0.04
0
Table 3: 12-15 minute request interval, updates
number of nodes
100
200
300
total requests
7981
11161
%good %bad
0.71
0.03
0.8
0
%not found %unanswered
0.25
0
0.2
Table 4: 0-30 second request interval, updates
17
0
6
Conclusions and Future Work
Due to the modular structure of Bamboo and the way that CVS interacts
with data, distCVS demonstrates that it is possible to build a complex peerto-peer system that can be rapidly upgraded to reflect any possible future
advances in the technology. Although distCVS is a working system, there
are still several areas where it could be improved.
distCVS is only a partial implementation of CVS, so although the framework has been built, there is still work to be done before the system supports
all of the functions offered by CVS. Along a similar vein, distCVS should also
be extended to retrieve entire projects at once from the network, which is
closer to how CVS interacts with source code repositories.
A deeper issue with distCVS, and one that would likely hamper any largescale deployment of the system, is the fact that all packets are sent as plain
text with no sort of authentication. If a malicious user wished to eavesdrop
on the files being transferred, create fake data, or even use a modified client to
corrupt the data stored on it, there is currently no way to detect or stop this.
Implementing some sort of encryption or node trust scheme would greatly
improve the utility of this system on an untrusted network.
Finally, a major shortcoming of distributed hash tables is that there is
no efficient way to search or index the contents stored on the network. Further research into this area could help solve one of the largest fundamental
problems that remain in peer-to-peer networks.
18
7
Appendix A: distCVS Source Listings
Listing 1: DistCVSStage.java
/*
* D i s t C V S S t a g e . java - a B a m b o o stage that i n t e r a c t s with CVS .
*
* C o p y r i g h t ( C ) 2004 ,2005 A n d r e w Ian Logan
* l o g a n a @ b c . edu , a n d r e w l o g a n @ g m a i l . com
*
*/
package thesis ;
i m p o r t b a m b o o . lss . A S y n c C o r e ;
i m p o r t b a m b o o . lss . D u s t D e v i l ;
i m p o r t b a m b o o . util . S t a n d a r d S t a g e ;
i m p o r t b a m b o o . util . G u i d T o o l s ;
i m p o r t java . math . B i g I n t e g e r ;
i m p o r t java . s e c u r i t y . M e s s a g e D i g e s t ;
import
import
import
import
import
import
import
import
java . util . Date ;
java . util . H a s h M a p ;
java . util . H a s h S e t ;
java . util . I t e r a t o r ;
java . util . R a n d o m ;
java . util . Set ;
java . util . L i n k e d L i s t ;
java . util . S t r i n g T o k e n i z e r ;
import
import
import
import
import
import
o s t o r e . util . B y t e U t i l s ; // for p r i n t _ b y t e s f u n c t i o n only
o s t o r e . util . S H A 1 H a s h ;
o s t o r e . util . S e c u r e H a s h ;
o s t o r e . util . Q u i c k S e r i a l i z a b l e ;
o s t o r e . util . I n p u t B u f f e r ;
o s t o r e . util . O u t p u t B u f f e r ;
import
import
import
import
import
seda . s a n d S t o r m . api . S t a g e s I n i t i a l i z e d S i g n a l ;
seda . s a n d S t o r m . api . C o n f i g D a t a I F ;
seda . s a n d S t o r m . api . Q u e u e E l e m e n t I F ;
seda . s a n d S t o r m . api . S i n g l e T h r e a d e d E v e n t H a n d l e r I F ;
seda . s a n d S t o r m . api . E v e n t H a n d l e r E x c e p t i o n ;
i m p o r t java . nio . B y t e B u f f e r ;
i m p o r t java . net . I n e t A d d r e s s ;
i m p o r t java . net . U n k n o w n H o s t E x c e p t i o n ;
i m p o r t b a m b o o . db . S t o r a g e M a n a g e r ;
import
import
import
import
import
import
import
import
import
b a m b o o . dht . G a t e w a y C l i e n t ;
b a m b o o . dht . b a m b o o _ p u t _ a r g s ;
b a m b o o . dht . b a m b o o _ g e t _ a r g s ;
b a m b o o . dht . b a m b o o _ v a l u e ;
b a m b o o . dht . b a m b o o _ s e c r e t ;
b a m b o o . dht . b a m b o o _ k e y ;
b a m b o o . dht . b a m b o o _ s t a t ;
b a m b o o . dht . b a m b o o _ p l a c e m a r k ;
b a m b o o . dht . b a m b o o _ g e t _ r e s ;
import
import
import
import
b a m b o o . dmgr . P u t O r R e m o v e R e q ;
b a m b o o . dmgr . P u t O r R e m o v e R e s p ;
b a m b o o . dmgr . F e t c h D a t a R e q ;
b a m b o o . dmgr . F e t c h D a t a R e s p ;
i m p o r t b a m b o o . dmgr . D a t a M a n a g e r ;
i m p o r t java . awt .*;
i m p o r t java . awt . event .*;
i m p o r t javax . swing .*;
i m p o r t java . io .*;
i
import
import
import
import
b a m b o o . api . B a m b o o R o u t e D e l i v e r ;
b a m b o o . api . B a m b o o R o u t e I n i t ;
b a m b o o . api . B a m b o o R o u t e r A p p R e g R e q ;
b a m b o o . api . B a m b o o R o u t e r A p p R e g R e s p ;
/**
* This file c o n t a i n s the f r o n t e n d and the logic for the D i s t C V S
* system .
*
* @ a u t h o r A n d r e w Logan
* @ v e r s i o n $Id : D i s t C V S S t a g e . java , v 1.11 2 0 0 5 / 0 2 / 0 3 0 6 : 3 1 : 4 8 a n d r e w Exp $
*/
p u b l i c class D i s t C V S S t a g e e x t e n d s S t a n d a r d S t a g e
implements SingleThreadedEventHandlerIF {
p r o t e c t e d s t a t i c final long a p p _ i d = b a m b o o . r o u t e r . R o u t e r . a p p _ i d ( D i s t C V S S t a g e . class );
p r o t e c t e d s t a t i c final int M A X _ F I L E S I Z E = 1 6 0 0 0 ;
p r o t e c t e d s t a t i c final b o o l e a n DEBUG = true ;
// how many s e c o n d s after we join the n e t w o r k do we start
// p r o c e s s i n g r e q u e s t s ?
// TODO : Make this c o n f i g u r a b l e ... or even better , some f u n c t i o n of
// n e t w o r k lag & the a m o u n t of data that we ’ re being sent .
p r o t e c t e d int i n i t _ d e l a y _ s e c = 15;
// t e s t i n g
protected
protected
protected
protected
protected
protected
protected
protected
protected
protected
protected
protected
protected
flag - will p e r f o r m reads / w r i t e s at r a n d o m i n t e r v a l s
b o o l e a n a u t o m a t i c _ t e s t = false ;
b o o l e a n u p d a t e r _ n o d e = false ;
b o o l e a n i n i t i a l _ d a t a = false ;
b o o l e a n s h o w _ g u i = true ;
b o o l e a n a u t o m a t i c _ d a t a _ s u b m i s s i o n _ h a c k = false ;
S t r i n g t e s t _ f i l e n a m e = null ;
S t r i n g t e s t _ p r o j e c t n a m e = null ;
S t r i n g l o g f i l e _ n a m e = null ;
int t e s t _ m i n w a i t = -1;
int t e s t _ m a x w a i t = -1;
int t e s t _ w a r m u p _ t i m e = -1;
int t e s t _ r u n _ t i m e = -1;
Date s t o p D a t e ;
p r o t e c t e d s t a t i c final long N O _ T I M E = -1;
protected BigInteger my_guid ;
// Used for t e s t i n g . F i l e n a m e s are f i l e p r e f i x + r a n d o m ( n u m _ f i l e s )
p r o t e c t e d S t r i n g f i l e _ p r e f i x = null ;
p r o t e c t e d int n u m _ f i l e s ;
// ttl c o n s t a n t s ( in s e c o n d s )
p r o t e c t e d s t a t i c final int O N E _ M I N U T E
p r o t e c t e d s t a t i c final int O N E _ H O U R
p r o t e c t e d s t a t i c final int O N E _ D A Y
p r o t e c t e d s t a t i c final int O N E _ W E E K
p r o t e c t e d s t a t i c final int O N E _ M O N T H
p r o t e c t e d s t a t i c final int O N E _ Y E A R
p r o t e c t e d s t a t i c final int M A X _ I N T
= 60;
= 60 * O N E _ M I N U T E ;
= 24 * O N E _ H O U R ;
=
7 * ONE_DAY ;
= 30 * O N E _ D A Y ;
= 365 * O N E _ D A Y ;
= Integer . MAX_VALUE ;
p r o t e c t e d L i n k e d L i s t w a i t _ q = new L i n k e d L i s t ();
protected
protected
protected
protected
protected
protected
protected
protected
protected
J F r a m e m a i n F r a m e = null ;
J P a n e l panel = null ;
J T e x t F i e l d f i l e n a m e F i e l d = null ;
J T e x t F i e l d p r o j e c t n a m e F i e l d = null ;
J L a b e l f i l e n a m e L a b e l = null ;
J L a b e l p r o j e c t n a m e L a b e l = null ;
J B u t t o n s u b m i t F i l e n a m e B u t t o n = null ;
J R a d i o B u t t o n p u t F i l e R a d i o B u t t o n = null ;
J R a d i o B u t t o n g e t F i l e R a d i o B u t t o n = null ;
p r o t e c t e d b o o l e a n r e t r i e v e F i l e = false ;
p r o t e c t e d b o o l e a n i n i t i a l i z e d = false ;
ii
////////////////////////////////////////////////////////////////////
// A c t i o n a d a p t e r for easy event - l i s t e n e r c o d i n g
class A c t i o n A d a p t e r i m p l e m e n t s A c t i o n L i s t e n e r
{
p u b l i c void a c t i o n P e r f o r m e d ( A c t i o n E v e n t e ) {}
}
////////////////////////////////////////////////////////////////////
p r o t e c t e d class G e t C V S F i l e E v e n t i m p l e m e n t s Q u e u e E l e m e n t I F {
public String filename ;
public String projectname ;
p u b l i c G e t C V S F i l e E v e n t ( S t r i n g filename , S t r i n g p r o j e c t n a m e ){
this . f i l e n a m e = f i l e n a m e ;
this . p r o j e c t n a m e = p r o j e c t n a m e ;
}
}
p r o t e c t e d class P u t C V S F i l e E v e n t i m p l e m e n t s Q u e u e E l e m e n t I F {
public String filename ;
public String projectname ;
p u b l i c P u t C V S F i l e E v e n t ( S t r i n g filename , S t r i n g p r o j e c t n a m e ){
this . f i l e n a m e = f i l e n a m e ;
this . p r o j e c t n a m e = p r o j e c t n a m e ;
}
}
// NOTE ! In order to be Q u i c k S e r i a l i z a b l e , the class has to be
// s t a t i c . Don ’ t know about p r o t e c t e d or void , but p r o b a b l y those
// as well .
p r o t e c t e d s t a t i c class N u l l P a y l o a d i m p l e m e n t s Q u i c k S e r i a l i z a b l e {
p u b l i c N u l l P a y l o a d (){};
p u b l i c N u l l P a y l o a d ( I n p u t B u f f e r b ){}
p u b l i c void s e r i a l i z e ( O u t p u t B u f f e r b ){}
p u b l i c S t r i n g t o S t r i n g (){
r e t u r n " N u l l P a y l o a d ";
}
}
// E n c a p s u l a t e a s t a t u s m e s s a g e .
p r o t e c t e d s t a t i c class S t a t u s P a y l o a d i m p l e m e n t s Q u i c k S e r i a l i z a b l e {
p u b l i c S t r i n g msg ;
p u b l i c S t a t u s P a y l o a d ( S t r i n g msg ){
this . msg = msg ;
}
p u b l i c S t a t u s P a y l o a d ( I n p u t B u f f e r b ){
msg = b . n e x t S t r i n g ();
}
p u b l i c void s e r i a l i z e ( O u t p u t B u f f e r b ){
b . add ( msg );
}
p u b l i c S t r i n g t o S t r i n g (){
r e t u r n msg ;
}
}
// Sent to p r i m a r y owner to i n i t i a t e p l a c i n g data into the s t o r a g e n e t w o r k .
p r o t e c t e d s t a t i c class P u t C V S R e q P a y l o a d i m p l e m e n t s Q u i c k S e r i a l i z a b l e {
public String filename ;
public String projectname ;
p u b l i c byte [] f i l e d a t a ;
p r i v a t e int f i l e s i z e ; // Just for the d e s e r i a l i z e r , o t h e r s s h o u l d get it from
filedata . length
p u b l i c P u t C V S R e q P a y l o a d ( S t r i n g filename , S t r i n g project n a m e , byte [] f i l e d a t a ){
this . f i l e n a m e = f i l e n a m e ;
this . p r o j e c t n a m e = p r o j e c t n a m e ;
this . f i l e d a t a = new byte [ f i l e d a t a . l e n g t h ];
this . f i l e d a t a = f i l e d a t a ;
iii
this . f i l e s i z e = f i l e d a t a . l e n g t h ;
S y s t e m . out . p r i n t l n (" P u t C V S R e q P a y l o a d : c o n s t r u c t o r ");
d e b u g _ d i s p _ f i l e ( this . filename , this . projectn a m e , this . f i l e d a t a );
}
p u b l i c P u t C V S R e q P a y l o a d ( I n p u t B u f f e r b ){
f i l e n a m e = b . n e x t S t r i n g ();
p r o j e c t n a m e = b . n e x t S t r i n g ();
f i l e s i z e = b . n e x t I n t ();
f i l e d a t a = new byte [ f i l e s i z e ];
b . n e x t B y t e s ( filedata , 0 , f i l e d a t a . l e n g t h );
S y s t e m . out . p r i n t l n (" P u t C V S R e q P a y l o a d : I n p u t B u f f e r ");
d e b u g _ d i s p _ f i l e ( this . filename , this . projectn a m e , this . f i l e d a t a );
}
p u b l i c void s e r i a l i z e ( O u t p u t B u f f e r b ){
S y s t e m . out . p r i n t l n (" p u t c v s r e q p a y l o a d : o u t p u t b u f f e r : start ");
b . add ( f i l e n a m e );
b . add ( p r o j e c t n a m e );
b . add ( f i l e s i z e );
b . add ( f i l e d a t a );
S y s t e m . out . p r i n t l n (" P u t C V S R e q P a y l o a d : s e r i a l i z e ");
d e b u g _ d i s p _ f i l e ( this . filename , this . projectn a m e , this . f i l e d a t a );
S y s t e m . out . p r i n t l n (" p u t c v s r e q p a y l o a d : o u t p u t b u f f e r : start ");
}
p u b l i c S t r i n g t o S t r i n g (){
r e t u r n " P u t C V S R e q P a y l o a d with f i l e n a m e : " + f i l e n a m e + " and p r o j e c t n a m e : " +
projectname ;
}
}
// Sent back by p r i m a r y owner to i n d i c a t e s u c c e s s or f a i l u r e . If
// the put o p e r a t i o n fails , m e s s a g e c o n t a i n s a d e s c r i p t i o n of why .
p r o t e c t e d s t a t i c class P u t C V S R e s p P a y l o a d i m p l e m e n t s Q u i c k S e r i a l i z a b l e {
p u b l i c b o o l e a n error ;
public String message ;
public String filename ;
public String projectname ;
p u b l i c byte [] v e r s i o n _ f i l e d a t a ;
p r i v a t e int f i l e s i z e ;
p u b l i c P u t C V S R e s p P a y l o a d ( b o o l e a n error , S t r i n g message , S t r i n g filename , S t r i n g
project n a m e , byte [] v e r s i o n _ f i l e d a t a ){
this . error = error ;
this . m e s s a g e = m e s s a g e ;
this . f i l e n a m e = f i l e n a m e ;
this . p r o j e c t n a m e = p r o j e c t n a m e ;
try {
this . v e r s i o n _ f i l e d a t a = new byte [ v e r s i o n _ f i l e d a t a . l e n g t h ];
this . v e r s i o n _ f i l e d a t a = v e r s i o n _ f i l e d a t a ;
this . f i l e s i z e = v e r s i o n _ f i l e d a t a . l e n g t h ;
}
catch ( N u l l P o i n t e r E x c e p t i o n npe ){
this . v e r s i o n _ f i l e d a t a = new byte [0];
this . f i l e s i z e = 0;
}
}
p u b l i c P u t C V S R e s p P a y l o a d ( I n p u t B u f f e r b ){
error = b . n e x t B o o l e a n ();
m e s s a g e = b . n e x t S t r i n g ();
f i l e n a m e = b . n e x t S t r i n g ();
p r o j e c t n a m e = b . n e x t S t r i n g ();
f i l e s i z e = b . n e x t I n t ();
v e r s i o n _ f i l e d a t a = new byte [ f i l e s i z e ];
b . n e x t B y t e s ( v e r s i o n _ f i l e d a t a , 0 , v e r s i o n _ f i l e d a t a . l e n g t h );
}
p u b l i c void s e r i a l i z e ( O u t p u t B u f f e r b ){
b . add ( error );
b . add ( m e s s a g e );
b . add ( f i l e n a m e );
b . add ( p r o j e c t n a m e );
b . add ( f i l e s i z e );
b . add ( v e r s i o n _ f i l e d a t a );
}
}
iv
// Sent to p r i m a r y owner to i n i t i a t e r e t r i e v a l of data from the
// s t o r a g e n e t w o r k .
p r o t e c t e d s t a t i c class G e t C V S R e q P a y l o a d i m p l e m e n t s Q u i c k S e r i a l i z a b l e {
public String filename ;
public String projectname ;
public boolean testing ;
p u b l i c G e t C V S R e q P a y l o a d ( S t r i n g filename , S t r i n g project n a m e , b o o l e a n t e s t i n g ){
this . f i l e n a m e = f i l e n a m e ;
this . p r o j e c t n a m e = p r o j e c t n a m e ;
this . t e s t i n g = t e s t i n g ;
}
p u b l i c G e t C V S R e q P a y l o a d ( I n p u t B u f f e r b ){
f i l e n a m e = b . n e x t S t r i n g ();
p r o j e c t n a m e = b . n e x t S t r i n g ();
t e s t i n g = b . n e x t B o o l e a n ();
}
p u b l i c void s e r i a l i z e ( O u t p u t B u f f e r b ){
b . add ( f i l e n a m e );
b . add ( p r o j e c t n a m e );
b . add ( t e s t i n g );
}
}
// Sent to r e q u e s t i n g node after r e t r i e v a l o p e r a t i o n o c c u r s . If
// s u c c e s s is false , then f i l e d a t a has l e n g t h zero .
p r o t e c t e d s t a t i c class G e t C V S R e s p P a y l o a d i m p l e m e n t s Q u i c k S e r i a l i z a b l e {
public String filename ;
public String projectname ;
public boolean success ;
p u b l i c byte [] f i l e d a t a ;
p u b l i c S t r i n g msg ;
p r i v a t e int f i l e s i z e ; // Just for the d e s e r i a l i z e r , o t h e r s s h o u l d get it from
filedata . length
public boolean testing ;
p u b l i c byte [] m a s t e r _ f i l e d a t a ;
p r i v a t e int m a s t e r _ f i l e s i z e ; // Just for the d e s e r i a l i z e r , o t h e r s s h o u l d get it from
filedata . length
p u b l i c G e t C V S R e s p P a y l o a d ( S t r i n g filename , S t r i n g project n a m e , b o o l e a n success , byte []
filedata , S t r i n g msg , b o o l e a n testing , byte [] m a s t e r _ f i l e d a t a ){
this . f i l e n a m e = f i l e n a m e ;
this . p r o j e c t n a m e = p r o j e c t n a m e ;
this . s u c c e s s = s u c c e s s ;
// TODO : Do I r e a l l y have to e n f o r c e this here ?
if ( s u c c e s s ){
this . f i l e d a t a = new byte [ f i l e d a t a . l e n g t h ];
this . f i l e d a t a = f i l e d a t a ;
this . f i l e s i z e = f i l e d a t a . l e n g t h ;
}
else {
// I guess ... At least it will have a . length , which
// is a b s e n t when null . (?)
this . f i l e s i z e = 0;
this . f i l e d a t a = new byte [0];
}
this . msg = msg ;
this . t e s t i n g = t e s t i n g ;
try {
this . m a s t e r _ f i l e d a t a = new byte [ m a s t e r _ f i l e d a t a . l e n g t h ];
this . m a s t e r _ f i l e d a t a = m a s t e r _ f i l e d a t a ;
this . m a s t e r _ f i l e s i z e = m a s t e r _ f i l e d a t a . l e n g t h ;
}
catch ( N u l l P o i n t e r E x c e p t i o n npe ){
this . m a s t e r _ f i l e d a t a = new byte [0];
this . m a s t e r _ f i l e s i z e = 0;
}
}
p u b l i c G e t C V S R e s p P a y l o a d ( I n p u t B u f f e r b ){
v
// I keep track of the l e n g t h here since I get an u n d e r f l o w
// error if I try to take more data from the byte b u f f e r
// than it a c t u a l l y has .
f i l e n a m e = b . n e x t S t r i n g ();
p r o j e c t n a m e = b . n e x t S t r i n g ();
s u c c e s s = b . n e x t B o o l e a n ();
f i l e s i z e = b . n e x t I n t ();
f i l e d a t a = new byte [ f i l e s i z e ];
b . n e x t B y t e s ( filedata , 0 , f i l e d a t a . l e n g t h );
msg = b . n e x t S t r i n g ();
t e s t i n g = b . n e x t B o o l e a n ();
m a s t e r _ f i l e s i z e = b . n e x t I n t ();
m a s t e r _ f i l e d a t a = new byte [ m a s t e r _ f i l e s i z e ];
b . n e x t B y t e s ( m a s t e r _ f i l e d a t a , 0 , m a s t e r _ f i l e d a t a . l e n g t h );
}
p u b l i c void s e r i a l i z e ( O u t p u t B u f f e r b ){
b . add ( f i l e n a m e );
b . add ( p r o j e c t n a m e );
b . add ( s u c c e s s );
b . add ( f i l e s i z e );
b . add ( f i l e d a t a );
b . add ( msg );
b . add ( t e s t i n g );
b . add ( m a s t e r _ f i l e s i z e );
b . add ( m a s t e r _ f i l e d a t a );
}
}
// Used on the p r i m a r y owner side to a t t a c h data to r e q u e s t s t h r o u g h the s y s t e m .
p r o t e c t e d class G u i d R e q I n f o C o n t a i n e r {
public String filename ;
public String projectname ;
p u b l i c B i g I n t e g e r src ;
p u b l i c long t i m e _ u s e c ;
p u b l i c byte [] f i l e d a t a ;
public boolean testing ;
p u b l i c G u i d R e q I n f o C o n t a i n e r ( S t r i n g filename , S t r i n g projectn a m e , B i g I n t e g e r src , b o o l e a n
t e s t i n g ){
this . f i l e n a m e = f i l e n a m e ;
this . p r o j e c t n a m e = p r o j e c t n a m e ;
this . src = src ;
this . t i m e _ u s e c = N O _ T I M E ;
this . f i l e d a t a = null ;
this . t e s t i n g = t e s t i n g ;
}
}
// Used on the p r i m a r y owner side to a t t a c h data to r e q u e s t s t h r o u g h the s y s t e m .
p r o t e c t e d class P u t C V S R e q I n f o C o n t a i n e r {
public String filename ;
public String projectname ;
p u b l i c B i g I n t e g e r src ;
p u b l i c long t i m e _ u s e c ;
p u b l i c byte [] f i l e d a t a ;
p u b l i c byte [] v e r s i o n _ f i l e d a t a ;
p u b l i c P u t C V S R e q I n f o C o n t a i n e r ( S t r i n g filename , S t r i n g project n a m e , byte [] filedata ,
B i g I n t e g e r src ){
this . f i l e n a m e = f i l e n a m e ;
this . p r o j e c t n a m e = p r o j e c t n a m e ;
this . src = src ;
this . t i m e _ u s e c = N O _ T I M E ;
this . f i l e d a t a = new byte [ f i l e d a t a . l e n g t h ];
this . f i l e d a t a = f i l e d a t a ;
this . v e r s i o n _ f i l e d a t a = v e r s i o n _ f i l e d a t a ;
}
}
// F o r c e s a delay b e t w e e n when the node i n t e g r a t e s into the n e t w o r k
// and when it b e g i n s s e n d i n g r e s p o n s e s . This was added to avoid
// r e t u r n i n g the wrong data when a node just i n t e g r a t e s into the
// s y s t e m .
p r o t e c t e d s t a t i c class I n t e g r a t i o n D e l a y F i n i s h e d A l a r m i m p l e m e n t s Q u e u e E l e m e n t I F {};
// For t e s t i n g p u r p o s e s only .
Will retrieve , modify , & s u b m i t a
vi
// s p e c i f i c file at r a n d o m i n t e r v a l s .
p r o t e c t e d s t a t i c class R e t r i e v e T e s t D a t a A l a r m i m p l e m e n t s Q u e u e E l e m e n t I F {};
p r o t e c t e d s t a t i c class S u b m i t T e s t D a t a A l a r m i m p l e m e n t s Q u e u e E l e m e n t I F {};
//
p r o t e c t e d s t a t i c class I n i t i a l D a t a A l a r m i m p l e m e n t s Q u e u e E l e m e n t I F {};
// A l e r t s the s y s t e m that the t e s t i n g w a r m u p time has been c o m p l e t e d .
p r o t e c t e d s t a t i c class W a r m u p C o m p l e t e d A l a r m i m p l e m e n t s Q u e u e E l e m e n t I F {};
// I don ’ t a c t u a l l y use this a n y m o r e .
public boolean die_on_get_failure ;
// C o n s t r u c t o r
p u b l i c D i s t C V S S t a g e () t h r o w s E x c e p t i o n {
// DEBUG = true ;
// R e g i s t e r p a y l o a d s
o s t o r e . util . T y p e T a b l e . r e g i s t e r _ t y p e ( N u l l P a y l o a d . class );
o s t o r e . util . T y p e T a b l e . r e g i s t e r _ t y p e ( S t a t u s P a y l o a d . class );
o s t o r e . util . T y p e T a b l e . r e g i s t e r _ t y p e ( G e t C V S R e q P a y l o a d . class );
o s t o r e . util . T y p e T a b l e . r e g i s t e r _ t y p e ( G e t C V S R e s p P a y l o a d . class );
o s t o r e . util . T y p e T a b l e . r e g i s t e r _ t y p e ( P u t C V S R e q P a y l o a d . class );
o s t o r e . util . T y p e T a b l e . r e g i s t e r _ t y p e ( P u t C V S R e s p P a y l o a d . class );
e v e n t _ t y p e s = new Class []{
S t a g e s I n i t i a l i z e d S i g n a l . class ,
P u t C V S F i l e E v e n t . class ,
G e t C V S F i l e E v e n t . class ,
P u t O r R e m o v e R e s p . class ,
S t o r a g e M a n a g e r . P u t R e s p . class ,
S t o r a g e M a n a g e r . G e t B y G u i d R e s p . class ,
S t o r a g e M a n a g e r . G e t B y T i m e R e s p . class ,
R e t r i e v e T e s t D a t a A l a r m . class ,
S u b m i t T e s t D a t a A l a r m . class ,
//
I n i t i a l D a t a A l a r m . class ,
W a r m u p C o m p l e t e d A l a r m . class ,
I n t e g r a t i o n D e l a y F i n i s h e d A l a r m . class
};
}
protected
protected
protected
protected
protected
protected
protected
protected
R a n d o m rand ;
Set puts = new H a s h S e t ();
MessageDigest digest ;
GatewayClient client ;
b a m b o o . lss . A S y n c C o r e acore ;
double mean_get_period_ms , mean_put_period_ms ;
int s t o r a g e _ g o a l ;
int t o t a l _ s t o r a g e ;
p r o t e c t e d s t a t i c d o u b l e r a n d o m _ e x p o n e n t i a l ( d o u b l e mean , R a n d o m rand ) {
d o u b l e u = rand . n e x t D o u b l e ();
r e t u r n (0 - ( mean * Math . log (1.0 - u )));
}
protected
protected
protected
protected
protected
int [] t t l _ v a l u e s = { 3600 , 24*3600 , 7 * 2 4 * 3 6 0 0 };
int [] p u t _ s i z e s = { 32 , 64 , 128 , 256 , 512 , 1024 };
long n e x t _ s e q ;
H a s h M a p p e n d i n g _ p u t s = new H a s h M a p ();
H a s h M a p p e n d i n g _ g e t s = new H a s h M a p ();
// cvs - ify the file .
p r o t e c t e d S t r i n g m a k e _ c v s _ f i l e ( S t r i n g i n i t i a l F i l e n a m e ) t h r o w s IOExcep t i o n , I n t e r r u p t e d E x c e p t i o n {
S y s t e m . out . p r i n t l n (" m a k e _ c v s _ f i l e :");
R u n t i m e r u n t i m e = R u n t i m e . g e t R u n t i m e ();
S t r i n g command , r e s u l t i n g F i l e n a m e ;
c o m m a n d = " pwd ";
P r o c e s s w h e r e A r e W e P r o c = r u n t i m e . exec ( c o m m a n d );
I n p u t S t r e a m i n p u t s t r e a m = w h e r e A r e W e P r o c . g e t I n p u t S t r e a m ();
I n p u t S t r e a m R e a d e r i n p u t s t r e a m r e a d e r = new I n p u t S t r e a m R e a d e r ( i n p u t s t r e a m );
B u f f e r e d R e a d e r b u f f e r e d r e a d e r = new B u f f e r e d R e a d e r ( i n p u t s t r e a m r e a d e r );
// read o u t p u t
S t r i n g line ;
while (( line = b u f f e r e d r e a d e r . r e a d L i n e ()) != null ){
vii
S y s t e m . out . p r i n t l n ( line );
}
c o m m a n d = "./ s t o r e h e l p e r . pl ";
r e s u l t i n g F i l e n a m e = i n i t i a l F i l e n a m e + " , v ";
P r o c e s s proc = r u n t i m e . exec ( c o m m a n d + i n i t i a l F i l e n a m e + " > s t o r e h e l p e r o u t p u t ");
// check for f a i l u r e
if ( proc . w a i t F o r () != 0){
S y s t e m . err . p r i n t l n (" Exit value = " + proc . e x i t V a l u e ());
throw new I n t e r r u p t e d E x c e p t i o n ();
}
return resultingFilename ;
}
// TODO : What to do ?
p u b l i c void d o _ a d d ( S t r i n g filename , S t r i n g p r o j e c t n a m e ){}
p u b l i c void d o _ u p d a t e ( S t r i n g filename , S t r i n g p r o j e c t n a m e ){}
p u b l i c void d o _ c h e c k i n ( S t r i n g filename , S t r i n g p r o j e c t n a m e ){}
p u b l i c void d o _ c h e c k o u t ( S t r i n g filename , S t r i n g p r o j e c t n a m e ){}
// TODO : end " what to do ?"
p u b l i c void d o _ p u t ( S t r i n g filename , S t r i n g p r o j e c t n a m e ){
S y s t e m . out . p r i n t l n (" D i s t C V S S t a g e : d o _ p u t ");
try {
byte [] f i l e d a t a = r e a d _ f i l e ( filename , p r o j e c t n a m e );
byte [] f i l e _ h e a d e r = null ;
byte [] c o m p l e t e d _ f i l e d a t a = null ;
// This will fail if it ’ s an add , so we catch that here .
try {
f i l e _ h e a d e r = r e a d _ f i l e ( f i l e n a m e +" _ v e r s i o n " , p r o j e c t n a m e );
c o m p l e t e d _ f i l e d a t a = (( new S t r i n g ( f i l e _ h e a d e r )) + ( new
S t r i n g ( f i l e d a t a ))). g e t B y t e s ();
}
// Null or a n e w l i n e ?
catch ( F i l e N o t F o u n d E x c e p t i o n fnfe ){
c o m p l e t e d _ f i l e d a t a = ( new S t r i n g ( f i l e d a t a )). g e t B y t e s ();
}
long now = n o w _ m s () * 1000;
int t t l _ s e c = 3 6 0 0 * 2 4 * 7 ;
/*
S t r i n g h a s h n a m e = p r o j e c t n a m e + ":" + f i l e n a m e ;
S e c u r e H a s h s e c u r e h a s h = new S H A 1 H a s h ( d i g e s t . d i g e s t ( h a s h n a m e . g e t B y t e s ()));
B i g I n t e g e r guid = G u i d T o o l s . s e c u r e _ h a s h _ t o _ b i g _ i n t e g e r ( s e c u r e h a s h );
*/
B i g I n t e g e r guid = m a k e _ h a s h n a m e ( filename , p r o j e c t n a m e );
B y t e B u f f e r bb = B y t e B u f f e r . wrap ( f i l e d a t a );
I n e t A d d r e s s c l i e n t A d d r e s s = I n e t A d d r e s s . g e t L o c a l H o s t ();
// < extra junk >
// byte [] dh = d a t a _ h a s h ( c o m p l e t e d _ f i l e d a t a );
// S y s t e m . out . p r i n t l n (" d a t a _ h a s h : 0 x " + B y t e U t i l s . p r i n t _ b y t e s ( dh , 0 , 8));
// </ extra junk >
// Place our data into the s y s t e m
// S t o r a g e M a n a g e r only acts locally , D a t a M a n a g e r wraps S t o r a g e M a n a g e r g l o b a l l y .
// c l a s s i f i e r . d i s p a t c h _ l a t e r ( new S t o r a g e M a n a g e r . P u t R e q ( key , bb , my_sink , " t e s t s t r i n g ") ,
0);
// c l a s s i f i e r . d i s p a t c h _ l a t e r ( new P u t O r R e m o v e R e q ( now , ttl_sec , guid , bb , true ,
c l i e n t A d d r e s s , my_sink , null ) , 0);
// c l a s s i f i e r . d i s p a t c h _ l a t e r ( new P u t C V S R e q ( filename , projectn a m e , f i l e d a t a ) , 0);
// D i s p a t c h data to p r i m a r y owner
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( guid , app_id , false , false , new
P u t C V S R e q P a y l o a d ( filename , projectn a m e , c o m p l e t e d _ f i l e d a t a )) , 0);
d e b u g _ d i s p _ f i l e ( filename , project n am e , f i l e d a t a );
l o g g e r . info (" Doing a put : f i l e n a m e : " + f i l e n a m e + " p r o j e c t n a m e : " + p r o j e c t n a m e );
viii
}
catch ( E x c e p t i o n e ){
e . p r i n t S t a c k T r a c e ();
S y s t e m . err . p r i n t l n (" Error !: " + e );
}
}
// TODO : Try to s p r e a d the load a c r o s s all of the nodes that store data , not just the p r i m a r y
owner .
p u b l i c void d o _ g e t ( S t r i n g filename , S t r i n g p r o j e c t n a m e ){
S y s t e m . out . p r i n t l n (" D i s t C V S S t a g e : d o _ g e t ");
b o o l e a n e r r o r C o n d i t i o n = false ;
S t r i n g r e s u l t i n g F i l e n a m e = new S t r i n g ();
try {
// TODO : Why do I still do this ? I don ’ t even use
// r e s u l t i n g F i l e n a m e a n y m o r e .
r e s u l t i n g F i l e n a m e = m a k e _ c v s _ f i l e ( f i l e n a m e );
}
catch ( E x c e p t i o n e ){
S y s t e m . out . p r i n t l n (" C a u g h t : " + e );
e r r o r C o n d i t i o n = true ;
}
if (! e r r o r C o n d i t i o n ){
try {
// byte [] f i l e a r r a y = new byte [ M A X _ F I L E S I Z E ];
// F i l e I n p u t S t r e a m fis = new F i l e I n p u t S t r e a m ( r e s u l t i n g F i l e n a m e );
/*
S t r i n g h a s h n a m e = p r o j e c t n a m e + ":" + f i l e n a m e ;
// Make guid
S e c u r e H a s h s e c u r e h a s h = new S H A 1 H a s h ( d i g e s t . d i g e s t ( h a s h n a m e . g e t B y t e s ()));
B i g I n t e g e r guid = G u i d T o o l s . s e c u r e _ h a s h _ t o _ b i g _ i n t e g e r ( s e c u r e h a s h );
*/
B i g I n t e g e r guid = m a k e _ h a s h n a m e ( filename , p r o j e c t n a m e );
// Send a m e s s a g e to p r i m a r y owner ( c l o s e s t to guid ).
// c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( guid , app_id , false , false , new
G U I D R e q P a y l o a d ( filename , p r o j e c t n a m e )) , 0);
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( guid , app_id , false , false , new
G e t C V S R e q P a y l o a d ( filename , projectn a m e , a u t o m a t i c _ t e s t )) , 0);
l o g g e r . info (" Doing a get :");
}
catch ( E x c e p t i o n e ){
e . p r i n t S t a c k T r a c e ();
S y s t e m . err . p r i n t l n (" Error !: " + e );
}
}
}
p u b l i c void init ( C o n f i g D a t a I F c o n f i g ) t h r o w s E x c e p t i o n {
super . init ( c o n f i g );
d i e _ o n _ g e t _ f a i l u r e = c o n f i g _ g e t _ b o o l e a n ( config , " d i e _ o n _ g e t _ f a i l u r e ");
m e a n _ p u t _ p e r i o d _ m s = c o n f i g _ g e t _ i n t ( config , " m e a n _ p u t _ p e r i o d _ m s ");
if ( m e a n _ p u t _ p e r i o d _ m s == -1.0)
mean_put_period_ms = 60.0*1000.0;
m e a n _ g e t _ p e r i o d _ m s = c o n f i g _ g e t _ i n t ( config , " m e a n _ g e t _ p e r i o d _ m s ");
if ( m e a n _ g e t _ p e r i o d _ m s == -1.0)
mean_get_period_ms = 60.0*1000.0;
s t o r a g e _ g o a l = c o n f i g _ g e t _ i n t ( config , " s t o r a g e _ g o a l ");
if ( s t o r a g e _ g o a l == -1)
storage_goal = 10*1024;
int seed = c o n f i g _ g e t _ i n t ( config , " seed ");
if ( seed == -1)
seed = (( int ) n o w _ m s ()) ^ m y _ n o d e _ i d . h a s h C o d e ();
rand = new R a n d o m ( seed );
try { d i g e s t = M e s s a g e D i g e s t . g e t I n s t a n c e (" SHA "); }
catch ( E x c e p t i o n e ) { a s s e r t false ; }
acore = D u s t D e v i l . a c o r e _ i n s t a n c e ();
S t r i n g c l i e n t _ s t g _ n a m e = c o n f i g _ g e t _ s t r i n g ( config , " c l i e n t _ s t a g e _ n a m e ");
l o g f i l e _ n a m e = c o n f i g _ g e t _ s t r i n g ( config , " l o g f i l e _ n a m e ");
S y s t e m . out . p r i n t l n (" l o g f i l e _ n a m e : " + l o g f i l e _ n a m e );
ix
c l i e n t = ( G a t e w a y C l i e n t ) l o o k u p _ s t a g e ( config , c l i e n t _ s t g _ n a m e );
a u t o m a t i c _ t e s t = c o n f i g _ g e t _ b o o l e a n ( config , " a u t o m a t i c _ t e s t ");
u p d a t e r _ n o d e = c o n f i g _ g e t _ b o o l e a n ( config , " u p d a t e r _ n o d e ");
i n i t i a l _ d a t a = c o n f i g _ g e t _ b o o l e a n ( config , " i n i t i a l _ d a t a ");
s h o w _ g u i = c o n f i g _ g e t _ b o o l e a n ( config , " s h o w _ g u i ");
a u t o m a t i c _ d a t a _ s u b m i s s i o n _ h a c k = c o n f i g _ g e t _ b o o l e a n ( config ,
" a u t o m a t i c _ d a t a _ s u b m i s s i o n _ h a c k ");
S y s t e m . out . p r i n t l n (" D i s t C V S S t a g e : i n i t i a l _ d a t a : " + i n i t i a l _ d a t a );
t e s t _ m a x w a i t = c o n f i g _ g e t _ i n t ( config , " t e s t _ m a x w a i t ");
if ( t e s t _ m a x w a i t == -1){
// m i l l i s e c o n d s
t e s t _ m a x w a i t = 60 * 1000;
}
t e s t _ m i n w a i t = c o n f i g _ g e t _ i n t ( config , " t e s t _ m i n w a i t ");
if ( t e s t _ m i n w a i t == -1){
// m i l l i s e c o n d s
t e s t _ m i n w a i t = 30 * 1000;
}
S y s t e m . out . p r i n t l n (" I n i t i a l i z a t i o n : t e s t _ m a x w a i t : " + t e s t _ m a x w a i t + " t e s t _ m i n w a i t : " +
t e s t _ m i n w a i t );
if ( a u t o m a t i c _ t e s t ){
t e s t _ f i l e n a m e = c o n f i g _ g e t _ s t r i n g ( config , " t e s t _ f i l e n a m e ");
if ( t e s t _ f i l e n a m e == null ){
S y s t e m . err . p r i n t l n (" Need to pass a t e s t _ f i l e n a m e if a u t o m a t i c _ t e s t is true !");
S y s t e m . exit (1);
}
t e s t _ p r o j e c t n a m e = c o n f i g _ g e t _ s t r i n g ( config , " t e s t _ p r o j e c t n a m e ");
if ( t e s t _ f i l e n a m e == null ){
S y s t e m . err . p r i n t l n (" Need to pass a t e s t _ p r o j e c t n a m e if a u t o m a t i c _ t e s t is true !");
S y s t e m . exit (1);
}
t e s t _ w a r m u p _ t i m e = c o n f i g _ g e t _ i n t ( config , " t e s t _ w a r m u p _ t i m e ");
if ( t e s t _ w a r m u p _ t i m e == -1){
// m i l l i s e c o n d s
t e s t _ w a r m u p _ t i m e = 0;
}
// -1 ( the d e f a u l t value ) i n d i c a t e s that the p r o g r a m s h o u l d
// run forever , a l t h o u g h r o u t i n e s c h e c k i n g for this s h o u l d
// first see if a u t o m a t i c _ t e s t is true .
t e s t _ r u n _ t i m e = c o n f i g _ g e t _ i n t ( config , " t e s t _ r u n _ t i m e ");
if ( t e s t _ r u n _ t i m e != -1){
// stop t e s t _ r u n _ t i m e s e c o n d s from now
s t o p D a t e = new Date ( t e s t _ r u n _ t i m e + (( new Date ()). g e t T i m e ()));
}
}
// Note ! Don ’ t u n c o m m e n t w i t h o u t r e m o v i n g the m y _ g u i d
// r e f e r e n c e in i n i t G U I ( t h r o w s a null p o i n t e r e x c e p t i o n )
// i n i t G U I ();
}
p u b l i c void h a n d l e E v e n t ( Q u e u e E l e m e n t I F elem ) t h r o w s E v e n t H a n d l e r E x c e p t i o n {
if ( l o g g e r . i s D e b u g E n a b l e d ()) l o g g e r . debug (" got " + elem );
S y s t e m . out . p r i n t l n (" D i s t C V S S t a g e : i n i t i a l i z e d :" + i n i t i a l i z e d );
if (! i n i t i a l i z e d ){
// sent after all s t a g e s have been i n i t i a l i z e d ( on this node )
if ( elem i n s t a n c e o f S t a g e s I n i t i a l i z e d S i g n a l ){
// R e q u e s t r e g i s t r a t i o n
d i s p a t c h ( new B a m b o o R o u t e r A p p R e g R e q ( app_id ,
false ,
false ,
false ,
m y _ s i n k ));
}
else if ( elem i n s t a n c e o f B a m b o o R o u t e r A p p R e g R e s p ){
// TODO : Add in some sort of delay s p e c i f i e d by the
// perl s c r i p t which will take into a c c o u n t the fact
// that the n e t w o r k needs some time to get c o n n e c t e d .
// Then , copy these r o u t i n e s into the F i n i s h e d
// n o t i f i c a t i o n for that m e s s a g e .
x
S y s t e m . out . p r i n t l n (" D i s t C V S S t a g e : got B a m b o o R o u t e r A p p R e g R e s p ");
B a m b o o R o u t e r A p p R e g R e s p resp = ( B a m b o o R o u t e r A p p R e g R e s p ) elem ;
m y _ g u i d = resp . n o d e _ g u i d ;
try { a p p e n d _ t o _ l o g f i l e (" Node s t a r t e d with s t o p D a t e =" + s t o p D a t e . t o S t r i n g () + "\ n ");}
catch ( I O E x c e p t i o n ioe ){ S y s t e m . err . p r i n t l n (" Error a p p e n d i n g to l o g f i l e !");}
// The delay on this m e s s a g e is how long we want to
// wait b e f o r e we begin p r o c e s s i n g m e s s a g e s . It s h o u l d
// be set a bit l o n g e r than the a v e r a g e a m o u n t of time
// it takes to give the right data to a node .
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new I n t e g r a t i o n D e l a y F i n i s h e d A l a r m () , i n i t _ d e l a y _ s e c *
1000);
}
else if ( elem i n s t a n c e o f I n t e g r a t i o n D e l a y F i n i s h e d A l a r m ){
S y s t e m . out . p r i n t l n (" D i s t C V S S t a g e : got I n t e g r a t i o n D e l a y F i n i s h e d A l a r m ");
// Now that we ’ re a m e m b e r of the network , allow the
// user to i n t e r a c t with the node . This was done
// b e c a u s e we won ’ t have m y _ g u i d until here , but it
// does make the GUI not show up until we ’ re i n t e g r a t e d
// into the n e t w o r k .
// TODO : Think about if this is the best s o l u t i o n .
// There must be a m e t h o d to c h a n g e the t i t l e b a r .
if ( s h o w _ g u i ){
i n i t G U I ();
}
// TODO : C l e a n u p !
// Are we a u t o m a t i n g the s u b m i t p r o c e s s ?
if ( a u t o m a t i c _ d a t a _ s u b m i s s i o n _ h a c k ){
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new P u t C V S F i l e E v e n t (" foo1 " , " foo1 ") , 0);
}
// Are we t e s t i n g the n e t w o r k ?
if ( a u t o m a t i c _ t e s t ){
if ( t e s t _ w a r m u p _ t i m e == -1){
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new W a r m u p C o m p l e t e d A l a r m () , 0);
}
else {
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new W a r m u p C o m p l e t e d A l a r m () , t e s t _ w a r m u p _ t i m e );
}
}
else {
i n i t i a l i z e d = true ;
try { a p p e n d _ t o _ l o g f i l e (" Node p r o c e s s i n g m e s s a g e s \ n ");}
catch ( I O E x c e p t i o n ioe ){ S y s t e m . err . p r i n t l n (" Error a p p e n d i n g to l o g f i l e !");}
// Clean out the queue that may have built up .
while (! w a i t _ q . i s E m p t y ()){
h a n d l e E v e n t (( Q u e u e E l e m e n t I F ) w a i t _ q . r e m o v e F i r s t ());
}
}
}
// B a m b o o R o u t e D e l i v e r m e s s a g e s are the only ones sent
// a c r o s s the n e t w o r k . See what we ’ ve got here .
else if ( elem i n s t a n c e o f B a m b o o R o u t e D e l i v e r ){
// Don ’ t want to lose it .
w a i t _ q . a d d L a s t ( elem );
B a m b o o R o u t e D e l i v e r info = ( B a m b o o R o u t e D e l i v e r ) elem ;
if ( info . p a y l o a d i n s t a n c e o f G e t C V S R e q P a y l o a d ){
G e t C V S R e q P a y l o a d pay = ( G e t C V S R e q P a y l o a d ) info . p a y l o a d ;
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false , false ,
new S t a t u s P a y l o a d (" I n i t i a l i z i n g d a t a b a s e - your r e q u e s t will be p r o c e s s e d s h o r t l y .")) , 0);
}
else if ( info . p a y l o a d i n s t a n c e o f P u t C V S R e q P a y l o a d ){
P u t C V S R e q P a y l o a d pay = ( P u t C V S R e q P a y l o a d ) info . p a y l o a d ;
xi
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false , false ,
new S t a t u s P a y l o a d (" I n i t i a l i z i n g d a t a b a s e - your r e q u e s t will be p r o c e s s e d s h o r t l y ")) , 0);
}
}
// W a r m u p C o m p l e t e d A l a r m m e s s a g e s are only sent if the s y s t e m is being t e s t e d .
else if ( elem i n s t a n c e o f W a r m u p C o m p l e t e d A l a r m ){
h a n d l e _ w a r m u p _ c o m p l e t e d _ a l a r m ();
}
else {
w a i t _ q . a d d L a s t ( elem );
}
}
else {
if ( elem i n s t a n c e o f G e t C V S F i l e E v e n t ){
G e t C V S F i l e E v e n t f i l e E v e n t = ( G e t C V S F i l e E v e n t ) elem ;
S y s t e m . out . p r i n t l n (" c a l l i n g d o _ g e t ");
d o _ g e t ( f i l e E v e n t . filename , f i l e E v e n t . p r o j e c t n a m e );
}
else if ( elem i n s t a n c e o f P u t C V S F i l e E v e n t ){
P u t C V S F i l e E v e n t f i l e E v e n t = ( P u t C V S F i l e E v e n t ) elem ;
d o _ p u t ( f i l e E v e n t . filename , f i l e E v e n t . p r o j e c t n a m e );
}
else if ( elem i n s t a n c e o f S t o r a g e M a n a g e r . P u t R e s p ){
S y s t e m . out . p r i n t l n (" Got a P u t R e s p : " + elem );
}
else if ( elem i n s t a n c e o f S t o r a g e M a n a g e r . G e t B y G u i d R e s p ){
h a n d l e _ g e t _ b y _ g u i d _ r e s p (( S t o r a g e M a n a g e r . G e t B y G u i d R e s p ) elem );
}
else if ( elem i n s t a n c e o f P u t O r R e m o v e R e s p ){
h a n d l e _ p u t _ o r _ r e m o v e _ r e s p (( P u t O r R e m o v e R e s p ) elem );
}
else if ( elem i n s t a n c e o f B a m b o o R o u t e D e l i v e r ){
h a n d l e _ b a m b o o _ r o u t e _ d e l i v e r (( B a m b o o R o u t e D e l i v e r ) elem );
}
// else if ( elem i n s t a n c e o f I n i t i a l D a t a A l a r m ){
// h a n d l e _ i n i t i a l _ d a t a _ a l a r m ();
//}
else if ( elem i n s t a n c e o f R e t r i e v e T e s t D a t a A l a r m ){
h a n d l e _ r e t r i e v e _ t e s t _ d a t a _ a l a r m ();
}
else if ( elem i n s t a n c e o f S u b m i t T e s t D a t a A l a r m ){
h a n d l e _ s u b m i t _ t e s t _ d a t a _ a l a r m ();
}
else {
BUG (" Event " + elem +" u n k n o w n ");
}
}
}
// TODO : Do s o m e t h i n g b e t t e r than have 16 K c h u n k s of file ( have to c h a n g e this is t o _ p u t as well )
p r o t e c t e d void h a n d l e _ g e t _ b y _ g u i d _ r e s p ( S t o r a g e M a n a g e r . G e t B y G u i d R e s p elem ){
S y s t e m . out . p r i n t l n (" D i s t C V S S t a g e : key : " + elem . key );
S y s t e m . out . p r i n t l n (" D i s t C V S S t a g e : data : " + elem . data );
S y s t e m . out . p r i n t l n (" D i s t C V S S t a g e : c o n t i n u a t i o n : " + elem . c o n t i n u a t i o n );
// S y s t e m . out . p r i n t l n (" D i s t C V S S t a g e : u s e r _ d a t a : " + ( S t r i n g ) elem . u s e r _ d a t a );
// Is there p o t e n t i a l l y more data to r e t r i e v e from the n e t w o r k ?
if ( elem . c o n t i n u a t i o n != null ){
if ( elem . u s e r _ d a t a i n s t a n c e o f G u i d R e q I n f o C o n t a i n e r ){
if ( elem . key != null ){
G u i d R e q I n f o C o n t a i n e r info = ( G u i d R e q I n f o C o n t a i n e r ) elem . u s e r _ d a t a ;
// Is the data we ’ re l o o k i n g at newer than the data we have s t o r e d ?
if ( elem . key . t i m e _ u s e c > info . t i m e _ u s e c ){
info . t i m e _ u s e c = elem . key . t i m e _ u s e c ;
info . f i l e d a t a = new byte [ elem . data . r e m a i n i n g ()];
elem . data . get ( info . f i l e d a t a );
}
}
else {
// I don ’ t think this can happen , so throw an error t e l l i n g me to i m p l e m e n t it
if it does .
BUG (" non - null c o n t i n u a t i o n with null key in a G u i d R e q I n f o C o n t a i n e r - have to
i m p l e m e n t s e n d i n g a file not found m e s s a g e .");
xii
// Note -- this is e s s e n t i a l l y the i m p l e m e n t a t i o n here , just make info valid
down here as well
// c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false , false ,
new G e t C V S R e s p P a y l o a d ( info . filename , info . project n a me , false , new byte [0] , " File not found .")) , 0);
}
}
else if ( elem . u s e r _ d a t a i n s t a n c e o f P u t C V S R e q I n f o C o n t a i n e r ){
if ( elem . key != null ){
P u t C V S R e q I n f o C o n t a i n e r info = ( P u t C V S R e q I n f o C o n t a i n e r ) elem . u s e r _ d a t a ;
// Are we l o o k i n g at newer data than what we have s t o r e d ?
if ( elem . key . t i m e _ u s e c > info . t i m e _ u s e c ){
info . t i m e _ u s e c = elem . key . t i m e _ u s e c ;
info . v e r s i o n _ f i l e d a t a = new byte [ elem . data . r e m a i n i n g ()];
elem . data . get ( info . v e r s i o n _ f i l e d a t a );
}
}
else {
// This would be the case where you ’ re a d d i n g data
// to the n e t w o r k for the first time . I r e a l l y
// don ’ t think this can happen , so I ’ ll throw an
// error if it does .
BUG (" non - null c o n t i n u a t i o n with null key in a P u t C V S R e q I n f o C o n t a i n e r - have to
i m p l e m e n t a d d i n g data in this case .");
}
}
else {
BUG (" i n v a l i d u s e r _ d a t a ");
}
// W h a t e v e r the u s e r _ d a t a is , the c o n t i n u a t i o n m e s s a g e is the same
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new S t o r a g e M a n a g e r . G e t B y G u i d C o n t ( elem . c o n t i n u a t i o n , false ,
my_sink , elem . u s e r _ d a t a ) , 0);
}
// c o n t i n u a t i o n is null , so we ’ ve l o o k e d t h r o u g h all of the data we need to .
else {
/* ( p r i m a r y owner )
* get data and r e t u r n it to a r e q u e s t i n g node .
*/
if ( elem . u s e r _ d a t a i n s t a n c e o f G u i d R e q I n f o C o n t a i n e r ){
G u i d R e q I n f o C o n t a i n e r info = ( G u i d R e q I n f o C o n t a i n e r ) elem . u s e r _ d a t a ;
// do we have data ?
if (( info . t i m e _ u s e c != N O _ T I M E ) && ( info . f i l e d a t a != null )){
byte [] r e t r i e v e d _ f i l e d a t a = info . f i l e d a t a ;
try {
// If we ’ re testing , o u t p u t that this is the
// p r i m a r y owner node . This i n f o r m a t i o n will
// be used to pick up where the p r i m a r y owner
// is .
if ( a u t o m a t i c _ t e s t ){
R u n t i m e r u n t i m e = R u n t i m e . g e t R u n t i m e ();
P r o c e s s proc = r u n t i m e . exec ("./ a p p e n d f i l e d a t a . pl " + " P R I M A R Y _ O W N E R :
s e r v i n g r e q u e s t ");
if ( proc . w a i t F o r () != 0){
S y s t e m . err . p r i n t l n (" Exit value = " + proc . e x i t V a l u e ());
throw new I n t e r r u p t e d E x c e p t i o n ();
}
}
// Alright , we know that e v e r y t h i n g up to the
// first n e w l i n e is a h e a d e r . Strip this out
// and write it to a s e p a r a t e file .
byte [] v e r s i o n _ h e a d e r = ((( new S t r i n g ( r e t r i e v e d _ f i l e d a t a )). split ("\\ n " ) ) [ 0 ]
+ "\ n "). g e t B y t e s ();
byte [] v e r s i o n _ f i l e d a t a = (( new
S t r i n g ( r e t r i e v e d _ f i l e d a t a )). s u b s t r i n g ( v e r s i o n _ h e a d e r . l e n g t h )). g e t B y t e s ();
S y s t e m . out . p r i n t l n (" G r a b b e d from the d a t a b a s e :");
d e b u g _ d i s p _ f i l e ( info . f i l e n a m e + " _ v e r s i o n " , info . project n a m e ,
v e r s i o n _ h e a d e r );
xiii
d e b u g _ d i s p _ f i l e ( info . f i l e n a m e +" , v " , info . project n a m e , v e r s i o n _ f i l e d a t a );
// I don ’ t need this , since I can just a p p e n d it to the r e c o n s t r u c t e d data .
// v e r s i o n file
// w r i t e _ f i l e ( info . f i l e n a m e + " _ v e r s i o n " , info . project n a m e , v e r s i o n _ h e a d e r );
// , v file
w r i t e _ f i l e ( info . f i l e n a m e + " , v " , info . project n a m e , v e r s i o n _ f i l e d a t a );
R u n t i m e r u n t i m e = R u n t i m e . g e t R u n t i m e ();
// does the r e q u i s i t e CVS c o m m a n d s
S t r i n g c o m m a n d = "./ r e c o n s t r u c t h e l p e r . pl ";
P r o c e s s proc = r u n t i m e . exec ( c o m m a n d + info . f i l e n a m e + " , v " + " >
h e l p e r o u t p u t " );
// check for f a i l u r e
if ( proc . w a i t F o r () != 0){
S y s t e m . err . p r i n t l n (" r e c o n s t r u c t h e l p e r exit value = " +
proc . e x i t V a l u e ());
// TODO : write new e x c e p t i o n that p a s s e s error code .
throw new I n t e r r u p t e d E x c e p t i o n ();
}
// So far so good . Read the newly r e c o n s t r u c t e d file off of the disk .
byte [] n e w _ f i l e d a t a = r e a d _ f i l e ( info . filename , info . p r o j e c t n a m e );
d e b u g _ d i s p _ f i l e ( info . filename , info . projectn a m e , n e w _ f i l e d a t a );
// Place the h e a d e r onto the new data .
byte [] c o m p l e t e d _ f i l e d a t a = (( new S t r i n g ( v e r s i o n _ h e a d e r )) + ( new
S t r i n g ( n e w _ f i l e d a t a ))). g e t B y t e s ();
// TODO : s h o u l d clean up t e m p o r a r y data .
byte [] m a s t e r _ f i l e d a t a = null ;
// Grab the m a s t e r f i l e d a t a
if ( a u t o m a t i c _ t e s t ){
m a s t e r _ f i l e d a t a = r e a d _ f i l e ("../ m a s t e r _ " + info . filename ,
info . p r o j e c t n a m e );
}
// Send the data back to the r e q u e s t i n g node
// c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false ,
false , new G U I D R e s p P a y l o a d ( info . filename , info . projectn a m e , f i l e d a t a )) , 0);
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false ,
false , new G e t C V S R e s p P a y l o a d ( info . filename , info . project n a m e , true , c o m p l e t e d _ f i l e d a t a , " OK " ,
info . testing , m a s t e r _ f i l e d a t a )) , 0);
}
catch ( I O E x c e p t i o n ioe ){
// I / O Error !
S y s t e m . err . p r i n t l n (" I / O error in h a n d l e _ g e t _ b y _ g u i d _ r e s p \ n " + ioe );
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false ,
false , new G e t C V S R e s p P a y l o a d ( info . filename , info . project n a m e , false , new byte [0] , " I / O error on
p a r e n t node ." , info . testing , new byte [0])) , 0);
}
catch ( I n t e r r u p t e d E x c e p t i o n ie ){
// s u b m i t h e l p e r error
S y s t e m . err . p r i n t l n (" r e c o n s t r u c t h e l p e r error \ n " + ie );
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false ,
false , new G e t C V S R e s p P a y l o a d ( info . filename , info . project n a m e , false , new byte [0] ,
" r e c o n s t r u c t h e l p e r . pl error on p a r e n t node ." , info . testing , new byte [0])) , 0);
}
}
else {
// If we can ’ t find it , then it doesn ’ t exist . Let the c l i e n t know this .
// c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false , false ,
new N u l l P a y l o a d ()) , 0);
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false , false ,
new G e t C V S R e s p P a y l o a d ( info . filename , info . project n a me , false , new byte [0] , " File not found ." ,
info . testing , new byte [0])) , 0);
}
}
/* ( p r i m a r y owner )
* u p d a t e a diff a l r e a d y in the d a t a b a s e .
xiv
*/
else if ( elem . u s e r _ d a t a i n s t a n c e o f P u t C V S R e q I n f o C o n t a i n e r ){
P u t C V S R e q I n f o C o n t a i n e r info = ( P u t C V S R e q I n f o C o n t a i n e r ) elem . u s e r _ d a t a ;
// do we have data ?
if (( info . t i m e _ u s e c != N O _ T I M E ) && ( info . v e r s i o n _ f i l e d a t a != null )){
// we r e t r i e v e d the , v file from the database , so use it to base the new v e r s i o n
on .
byte [] r e t r i e v e d _ f i l e d a t a = info . v e r s i o n _ f i l e d a t a ;
try {
// Alright , we know that e v e r y t h i n g up to the
// first n e w l i n e is a h e a d e r . Strip this out
// and write it to a s e p a r a t e file .
byte [] r e t r i e v e d _ v e r s i o n _ h e a d e r = ((( new
S t r i n g ( r e t r i e v e d _ f i l e d a t a )). split ("\\ n " ) ) [ 0 ] + "\ n "). g e t B y t e s ();
byte [] r e t r i e v e d _ v e r s i o n _ f i l e d a t a = (( new
S t r i n g ( r e t r i e v e d _ f i l e d a t a )). s u b s t r i n g ( r e t r i e v e d _ v e r s i o n _ h e a d e r . l e n g t h )). g e t B y t e s ();
byte [] s u b m i t t e d _ v e r s i o n _ h e a d e r = ((( new
S t r i n g ( info . f i l e d a t a )). split ("\\ n " ) ) [ 0 ] + "\ n "). g e t B y t e s ();
byte [] s u b m i t t e d _ v e r s i o n _ f i l e d a t a = (( new
S t r i n g ( info . f i l e d a t a )). s u b s t r i n g ( r e t r i e v e d _ v e r s i o n _ h e a d e r . l e n g t h )). g e t B y t e s ();
// r e t r i e v e d v e r s i o n file
w r i t e _ f i l e ( info . f i l e n a m e + " , v _ v e r s i o n " , info . project n a m e ,
r e t r i e v e d _ v e r s i o n _ h e a d e r );
// , v file
w r i t e _ f i l e ( info . f i l e n a m e + " , v " , info . project n a m e ,
r e t r i e v e d _ v e r s i o n _ f i l e d a t a );
// S u b m i t t e d v e r s i o n .
w r i t e _ f i l e ( info . f i l e n a m e + " _ v e r s i o n " , info . projectn a m e ,
s u b m i t t e d _ v e r s i o n _ h e a d e r );
// S u b m i t t e d u p d a t e .
w r i t e _ f i l e ( info . filename , info . projectn a m e , s u b m i t t e d _ v e r s i o n _ f i l e d a t a );
S y s t e m . out . p r i n t l n (" r e c o n s t r u c t i o n stage :");
d e b u g _ d i s p _ f i l e ( info . f i l e n a m e + " , v _ v e r s i o n " , info . project n am e ,
r e t r i e v e d _ v e r s i o n _ h e a d e r );
d e b u g _ d i s p _ f i l e ( info . f i l e n a m e + " , v " , info . project na m e ,
r e t r i e v e d _ v e r s i o n _ f i l e d a t a );
d e b u g _ d i s p _ f i l e ( info . f i l e n a m e + " _ v e r s i o n " , info . project n a m e ,
s u b m i t t e d _ v e r s i o n _ h e a d e r );
d e b u g _ d i s p _ f i l e ( info . filename , info . projectn a m e ,
s u b m i t t e d _ v e r s i o n _ f i l e d a t a );
R u n t i m e r u n t i m e = R u n t i m e . g e t R u n t i m e ();
// does the r e q u i s i t e CVS c o m m a n d s
S t r i n g c o m m a n d = "./ s u b m i t h e l p e r . pl ";
P r o c e s s proc = r u n t i m e . exec ( c o m m a n d + info . f i l e n a m e +" >
s u b m i t h e l p e r o u t p u t ");
// check for f a i l u r e
// TODO : Will a n o n z e r o r e t u r n value pass over
// the rest of the code ?
if ( proc . w a i t F o r () != 0){
S y s t e m . err . p r i n t l n (" s u b m i t h e l p e r exit value = " + proc . e x i t V a l u e ());
// TODO : write new e x c e p t i o n that p a s s e s error code .
throw new I n t e r r u p t e d E x c e p t i o n ();
}
// So far so good . Read the new v e r s i o n and , v
// files off of the disk , put them together ,
// and then i n s e r t them into the d a t a b a s e .
byte [] n e w _ v e r s i o n _ h e a d e r = r e a d _ f i l e ( info . f i l e n a m e + " , v _ v e r s i o n " ,
info . p r o j e c t n a m e );
byte [] n e w _ v e r s i o n _ d a t a = r e a d _ f i l e ( info . f i l e n a m e + " , v " , info . p r o j e c t n a m e );
byte [] n e w _ f i l e d a t a = (( new S t r i n g ( n e w _ v e r s i o n _ h e a d e r )) + ( new
S t r i n g ( n e w _ v e r s i o n _ d a t a ))). g e t B y t e s ();
xv
d e b u g _ d i s p _ f i l e ( info . f i l e n a m e +" , v _ v e r s i o n " ,
info . project n am e ,
n e w _ v e r s i o n _ h e a d e r );
d e b u g _ d i s p _ f i l e ( info . f i l e n a m e +" , v " ,
d e b u g _ d i s p _ f i l e ( info . f i l e n a m e +" , v " ,
s u b m i t t e d _ v e r s i o n _ f i l e d a t a );
info . project na m e , n e w _ v e r s i o n _ d a t a );
info . project na m e ,
// Place the v e r s i o n data into info
info . v e r s i o n _ f i l e d a t a = n e w _ v e r s i o n _ h e a d e r ;
long now = n o w _ m s () * 1000;
// Note !
I don ’ t have elem . key a n y m o r e .
// TODO : Make the c l i e n t pass t t l _ s e c along
// with file write r e q u e s t s .
int t t l _ s e c = O N E _ W E E K ;
/*
S t r i n g h a s h n a m e = info . p r o j e c t n a m e + ":" + info . f i l e n a m e ;
S e c u r e H a s h s e c u r e h a s h = new S H A 1 H a s h ( d i g e s t . d i g e s t ( h a s h n a m e . g e t B y t e s ()));
B i g I n t e g e r guid = G u i d T o o l s . s e c u r e _ h a s h _ t o _ b i g _ i n t e g e r ( s e c u r e h a s h );
*/
B i g I n t e g e r guid = m a k e _ h a s h n a m e ( info . filename , info . p r o j e c t n a m e );
// guid doesn ’ t change , so why r e c a l c u l a t e it ? -- b e c a u s e now we don ’ t have
it a n y m o r e .
// B i g I n t e g e r guid = elem . key . guid ;
B y t e B u f f e r bb = B y t e B u f f e r . wrap ( n e w _ f i l e d a t a );
I n e t A d d r e s s c l i e n t A d d r e s s = I n e t A d d r e s s . g e t L o c a l H o s t ();
// TODO : Make this work .
// d e l e t e ( r e c y c l e ?) the old one
// c l a s s i f i e r . d i s p a t c h _ l a t e r ( new P u t O r R e m o v e R e q (/* elem . key . t i m e _ u s e c */ now ,
elem . key . ttl_sec , elem . key . guid , B y t e B u f f e r . wrap ( v e r s i o n _ f i l e d a t a ) , false , c l i e n t A d d r e s s , my_sink ,
null ) , 0);
// s u b m i t the new one .
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new P u t O r R e m o v e R e q ( now , ttl_sec , guid , bb , true ,
c l i e n t A d d r e s s , my_sink , info ) , 0);
}
catch ( I O E x c e p t i o n ioe ){
S y s t e m . err . p r i n t l n (" I / O error !:\ n " + ioe );
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false ,
false , new P u t C V S R e s p P a y l o a d ( true , " I / O error on p a r e n t node " , info . filename , info . project n a me ,
null )) , 0);
}
catch ( I n t e r r u p t e d E x c e p t i o n ie ){
S y s t e m . err . p r i n t l n (" P r o b l e m with s u b m i t h e l p e r . pl !\ n " + ie );
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false ,
false , new P u t C V S R e s p P a y l o a d ( true , " s u b m i t h e l p e r . pl p r o b l e m on p a r e n t node " , info . filename ,
info . project n a me , null )) , 0);
}
}
else {
// NOTE : This is also the case if the data is being
// added for the first time .
// TODO : This is an ugly i m p l e m e n t a t i o n - we s h o u l d
// have the c l i e n t s p e c i f i c a l l y ask for an add , not
// just a s s u m e that one is w a n t e d when the file is not
// found .
// c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false , false ,
new P u t C V S R e s p P a y l o a d ( true , " File not found in d a t a b a s e - a t t e m p t i n g to add " , info . filename ,
info . project n a me , null )) , 0);
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false , false ,
new S t a t u s P a y l o a d (" File not found in database , p e r f o r m i n g an add \ n ")) , 0);
try {
d e b u g _ d i s p _ f i l e ( info . filename , info . projectn a m e , info . f i l e d a t a );
// S u b m i t t e d file .
w r i t e _ f i l e ( info . filename , info . projectn a m e , info . f i l e d a t a );
// Turn it into a , v file .
S t r i n g n e w _ f i l e n a m e = m a k e _ c v s _ f i l e ( info . f i l e n a m e );
// grab the r e s u l t i n g file
xvi
byte [] n e w _ f i l e d a t a = r e a d _ f i l e ( n e w _ f i l e n a m e , info . p r o j e c t n a m e );
byte [] n e w _ f i l e d a t a _ v e r s i o n = r e a d _ f i l e ( n e w _ f i l e n a m e + " _ v e r s i o n " ,
info . p r o j e c t n a m e );
info . v e r s i o n _ f i l e d a t a = n e w _ f i l e d a t a _ v e r s i o n ;
d e b u g _ d i s p _ f i l e ( n e w _ f i l e n a m e , info . project na m e , n e w _ f i l e d a t a );
d e b u g _ d i s p _ f i l e ( n e w _ f i l e n a m e + " _ v e r s i o n ( a d d i n g file )" , info . project n a m e ,
n e w _ f i l e d a t a _ v e r s i o n );
// Place the h e a d e r onto the new data .
byte [] c o m p l e t e d _ f i l e d a t a = (( new S t r i n g ( n e w _ f i l e d a t a _ v e r s i o n )) + ( new
S t r i n g ( n e w _ f i l e d a t a ))). g e t B y t e s ();
d e b u g _ d i s p _ f i l e (" c o m p l e t e d _ f i l e d a t a " , info . project na m e , c o m p l e t e d _ f i l e d a t a );
// If we ’ re testing , write the m a s t e r copy of
// the data to the f i l e s y s t e m ( we ’ re being run
// in our own directory , so keep one c e n t r a l
// copy of this ).
/*
if ( a u t o m a t i c _ t e s t ){
// I want the most r e c e n t update , not the most r e c e n t ,v file .
try { w r i t e _ f i l e ("../ m a s t e r _ "+ info . filename , info . projectn a m e ,
info . f i l e d a t a );}
catch ( I O E x c e p t i o n ioe ){
BUG ( ioe );
}
}
*/
// place it into the d a t a b a s e
long now = n o w _ m s () * 1000;
int t t l _ s e c = O N E _ W E E K ;
/*
S t r i n g h a s h n a m e = info . p r o j e c t n a m e + ":" + info . f i l e n a m e ;
S e c u r e H a s h s e c u r e h a s h = new S H A 1 H a s h ( d i g e s t . d i g e s t ( h a s h n a m e . g e t B y t e s ()));
B i g I n t e g e r guid = G u i d T o o l s . s e c u r e _ h a s h _ t o _ b i g _ i n t e g e r ( s e c u r e h a s h );
*/
B i g I n t e g e r guid = m a k e _ h a s h n a m e ( info . filename , info . p r o j e c t n a m e );
B y t e B u f f e r bb = B y t e B u f f e r . wrap ( c o m p l e t e d _ f i l e d a t a );
I n e t A d d r e s s c l i e n t A d d r e s s = I n e t A d d r e s s . g e t L o c a l H o s t ();
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new P u t O r R e m o v e R e q ( now , ttl_sec , guid , bb , true ,
c l i e n t A d d r e s s , my_sink , info ) , 0);
}
catch ( I O E x c e p t i o n ioe ){
S y s t e m . err . p r i n t l n (" I / O Error !\ n " + ioe );
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false ,
false , new P u t C V S R e s p P a y l o a d ( true , " Add o p e r a t i o n f a i l e d - I / O error on p r i m a r y owner ." ,
info . filename , info . project n a m e , null )) , 0);
}
catch ( I n t e r r u p t e d E x c e p t i o n ie ){
S y s t e m . err . p r i n t l n (" Error r u n n i n g s t o r e h e l p e r . pl !\ n " + ie );
}
}
}
else {
BUG (" i n v a l i d u s e r _ d a t a ");
}
}
}
// We ’ ve r e c i e v e d n o t i f i c a t i o n that our P u t O r R e m o v e R e q was
// processed , so send a m e s s a g e back to the r e q u e s t i n g node t e l l i n g
// it that the s u b m i t is c o m p l e t e .
p r o t e c t e d void h a n d l e _ p u t _ o r _ r e m o v e _ r e s p ( P u t O r R e m o v e R e s p elem ){
if ( elem . u s e r _ d a t a i n s t a n c e o f P u t C V S R e q I n f o C o n t a i n e r ){
S y s t e m . out . p r i n t l n (" R e c i e v e d known P u t O r R e m o v e R e s p : " + elem );
P u t C V S R e q I n f o C o n t a i n e r info = ( P u t C V S R e q I n f o C o n t a i n e r ) elem . u s e r _ d a t a ;
// If we ’ re testing , write the m a s t e r copy of the data to
// the f i l e s y s t e m ( we ’ re being run in our own director y , so
// keep one c e n t r a l copy of this ).
if ( a u t o m a t i c _ t e s t ){
xvii
// Strip out the h e a d e r that ’ s i n c l u d e d in info . f i l e d a t a
byte [] m a s t e r _ v e r s i o n _ h e a d e r = ((( new S t r i n g ( info . f i l e d a t a )). split ("\\ n " ) ) [ 0 ] +
"\ n "). g e t B y t e s ();
byte [] m a s t e r _ v e r s i o n _ f i l e d a t a = (( new
S t r i n g ( info . f i l e d a t a )). s u b s t r i n g ( m a s t e r _ v e r s i o n _ h e a d e r . l e n g t h )). g e t B y t e s ();
// I want the most r e c e n t update , not the most r e c e n t ,v file .
// TODO : Clean this up
// TODO : Fix the fact that there is no h e a d e r on an add .
// $line =~ s /\/ $ i n p u t f i l e \ / [ 0 - 9 ] \ . [ 0 - 9 ] \ / ( . * ) / \ / $ i n p u t f i l e \/ $ v e r s i o n n u m \/ $1 / gi ;
// If we ’ re v e r s i o n 1.1.1.1 , we ’ re an add .
S t r i n g temp = ( new S t r i n g ( info . v e r s i o n _ f i l e d a t a )). s u b s t r i n g (0 ,
10+ info . f i l e n a m e . l e n g t h ());
S y s t e m . out . p r i n t l n ( " * * * * temp : " + temp );
if ( temp . e q u a l s ( new S t r i n g ("/" + info . f i l e n a m e + " / 1 . 1 . 1 . 1 / " ) ) ) {
S y s t e m . out . p r i n t l n ( " * * * * * ADD V E R S I O N D E T E C T E D * * * * * " ) ;
m a s t e r _ v e r s i o n _ f i l e d a t a = info . f i l e d a t a ;
}
try { w r i t e _ f i l e ("../ m a s t e r _ "+ info . filename , info . projectn a m e ,
m a s t e r _ v e r s i o n _ f i l e d a t a );}
catch ( I O E x c e p t i o n ioe ){
BUG ( ioe );
}
}
// TODO :
This is a hack .
Clean this up .
d e b u g _ d i s p _ f i l e ( info . f i l e n a m e + " _ v e r s i o n ( h a n d l e _ p u t _ o r _ r e m o v e _ r e s p )" ,
info . project n a me , info . v e r s i o n _ f i l e d a t a );
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new B a m b o o R o u t e I n i t ( info . src , app_id , false , false , new
P u t C V S R e s p P a y l o a d ( false , " OK " , info . filename , info . projectn a m e , info . v e r s i o n _ f i l e d a t a )) , 0);
}
else {
S y s t e m . out . p r i n t l n (" R e c i e v e d u n k n o w n P u t O r R e m o v e R e s p : " + elem );
}
}
p r o t e c t e d void h a n d l e _ b a m b o o _ r o u t e _ d e l i v e r ( B a m b o o R o u t e D e l i v e r elem ){
S y s t e m . out . p r i n t l n (" R e c i e v e d B a m b o o R o u t e D e l i v e r from : " + elem . src );
// We ’ re the p r i m a r y owner of a piece of data , and s o m e o n e wants it .
if ( elem . p a y l o a d i n s t a n c e o f G e t C V S R e q P a y l o a d ){
G e t C V S R e q P a y l o a d pay = ( G e t C V S R e q P a y l o a d ) elem . p a y l o a d ;
// D e s t i n a t i o n GUID is set e a r l i e r to the GUID of the file we want .
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new S t o r a g e M a n a g e r . G e t B y G u i d R e q ( elem . dest , true , null ,
my_sink , new G u i d R e q I n f o C o n t a i n e r ( pay . filename , pay . projectn a m e , elem . src , pay . t e s t i n g )) , 0);
}
// We ’ re the r e q u e s t i n g node , and we ’ d r e q u e s t e d some data ( e a r l i e r )
else if ( elem . p a y l o a d i n s t a n c e o f G e t C V S R e s p P a y l o a d ){
G e t C V S R e s p P a y l o a d pay = ( G e t C V S R e s p P a y l o a d ) elem . p a y l o a d ;
// If the dest guid is equal to our guid , then this must be
// a r e s p o n s e to a m e s s a g e we sent out e a r l i e r .
if ( elem . dest . e q u a l s ( m y _ g u i d )){
d e b u g _ p r i n t l n (" Got a B a m b o o R o u t e D e l i v e r with m a t c h i n g guid !");
if ( pay . s u c c e s s ){
// o u t p u t to s c r e e n
S y s t e m . out . p r i n t l n (" f i l e n a m e : " + pay . f i l e n a m e + " p r o j e c t n a m e : " +
pay . p r o j e c t n a m e );
S y s t e m . out . p r i n t l n (" -= -= -= contents -= -= -=");
for ( int i = 0; i < pay . f i l e d a t a . l e n g t h ; i ++){
S y s t e m . out . print (( char ) pay . f i l e d a t a [ i ]);
}
S y s t e m . out . p r i n t l n (" -= -= -= e n d _ c o n t e n t s -= -= -=");
xviii
// Now , write to a file
try {
byte [] v e r s i o n _ h e a d e r = ((( new S t r i n g ( pay . f i l e d a t a )). split ("\\ n " ) ) [ 0 ] +
"\ n "). g e t B y t e s ();
byte [] f i l e d a t a = (( new
S t r i n g ( pay . f i l e d a t a )). s u b s t r i n g ( v e r s i o n _ h e a d e r . l e n g t h )). g e t B y t e s ();
// Open a v e r s i o n file and o v e r w r i t e w h a t e v e r a l r e a d y e x i s t s .
F i l e O u t p u t S t r e a m v e r s i o n _ f o s = new F i l e O u t p u t S t r e a m ( pay . f i l e n a m e +
" _ v e r s i o n ");
v e r s i o n _ f o s . write ( v e r s i o n _ h e a d e r );
v e r s i o n _ f o s . close ();
// Open a file and o v e r w r i t e w h a t e v e r a l r e a d y e x i s t s .
F i l e O u t p u t S t r e a m fos = new F i l e O u t p u t S t r e a m ( pay . f i l e n a m e );
here ?
// write f i l e d a t a . l e n g t h bytes to f i l e s y s t e m
// TODO : Does the byte order of the s u b m i t t i n g s y s t e m make a d i f f e r e n c e
How about Windows < - > Linux ?
fos . write ( f i l e d a t a );
// done !
fos . close ();
// Are we t e s t i n g the s y s t e m ?
if ( pay . t e s t i n g ){
try {
// O u t p u t a local m a s t e r
w r i t e _ f i l e (" m a s t e r _ "+ pay . filename , pay . project n am e ,
pay . m a s t e r _ f i l e d a t a );
// See if the data is c o r r e c t
R u n t i m e r u n t i m e = R u n t i m e . g e t R u n t i m e ();
// C h a n g e d to now check local m a s t e r
P r o c e s s proc = r u n t i m e . exec ("./ d i f f _ w i t h _ m a s t e r . pl " +
t e s t _ f i l e n a m e );
// Note ! Must wait for these p r o c e s s e s to exit b e f o r e c o n t i n u i n g !
if ( proc . w a i t F o r () != 0){
S y s t e m . err . p r i n t l n (" Exit value = " + proc . e x i t V a l u e ());
throw new I n t e r r u p t e d E x c e p t i o n ();
}
int n e x t _ r e q u e s t _ t i m e = m a k e _ r a n d o m _ i n t ( t e s t _ m i n w a i t , t e s t _ m a x w a i t );
Date n e x t _ r e q u e s t _ d a t e = new Date ((( new Date ()). g e t T i m e ()) +
( long ) n e x t _ r e q u e s t _ t i m e );
try { a p p e n d _ t o _ l o g f i l e (" n e x t _ r e q u e s t _ d a t e ( u p d a t e r ):" +
n e x t _ r e q u e s t _ d a t e + "\ n ");}
catch ( I O E x c e p t i o n ioe ){ S y s t e m . err . p r i n t l n (" Error a p p e n d i n g to
l o g f i l e !");}
// will this r e q u e s t occur b e f o r e the c u t o f f time ?
if ( n e x t _ r e q u e s t _ d a t e . b e f o r e ( s t o p D a t e )){
// C o n s t r u c t some new data after a r a n d o m i n t e r v a l has p a s s e d .
if ( u p d a t e r _ n o d e ){
d e b u g _ p r i n t l n (" s e n d i n g S u b m i t T e s t D a t a A l a r m ()");
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new S u b m i t T e s t D a t a A l a r m () , 0);
}
else {
d e b u g _ p r i n t l n (" q u e u e i n g R e t r i e v e T e s t D a t a A l a r m ()");
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new R e t r i e v e T e s t D a t a A l a r m () ,
n e x t _ r e q u e s t _ t i m e );
}
}
else {
try { a p p e n d _ t o _ l o g f i l e (" s t o p D a t e r e a c h e d . E n d i n g r e q u e s t s .\ n ");}
catch ( I O E x c e p t i o n ioe ){ S y s t e m . err . p r i n t l n (" Error a p p e n d i n g to
l o g f i l e !");}
}
}
catch ( I O E x c e p t i o n ioe ){
S y s t e m . out . p r i n t l n (" Error c a l l i n g d i f f _ w i t h _ m a s t e r . pl !");
}
xix
catch ( I n t e r r u p t e d E x c e p t i o n ie ){
S y s t e m . out . p r i n t l n (" d i f f _ w i t h _ m a s t e r . pl had n o n z e r o exit s t a t u s !");
}
}
}
catch ( I O E x c e p t i o n ioe ){
S y s t e m . err . p r i n t l n (" Error w r i t i n g r e t r i e v e d file to f i l e s y s t e m : " + ioe );
}
}
else {
S y s t e m . out . p r i n t l n (" -= -= -=");
S y s t e m . err . p r i n t l n ( pay . msg );
S y s t e m . out . p r i n t l n (" -= -= -=");
try {
// Yes , I am g e t t i n g lazy .
R u n t i m e r u n t i m e = R u n t i m e . g e t R u n t i m e ();
P r o c e s s proc = r u n t i m e . exec ("./ a p p e n d _ n o t _ f o u n d . pl ");
// Note ! Must wait for these p r o c e s s e s to exit b e f o r e c o n t i n u i n g !
if ( proc . w a i t F o r () != 0){
S y s t e m . err . p r i n t l n (" Exit value = " + proc . e x i t V a l u e ());
throw new I n t e r r u p t e d E x c e p t i o n ();
}
}
catch ( I O E x c e p t i o n ioe ){
S y s t e m . out . p r i n t l n (" Error c a l l i n g ./ a p p e n d _ n o t _ f o u n d . pl !");
}
catch ( I n t e r r u p t e d E x c e p t i o n ie ){
S y s t e m . out . p r i n t l n ("./ a p p e n d _ n o t _ f o u n d . pl e x i t e d with n o n z e r o code !");
}
d e b u g _ p r i n t l n (" q u e u e i n g R e t r i e v e T e s t D a t a A l a r m ()");
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new R e t r i e v e T e s t D a t a A l a r m () ,
m a k e _ r a n d o m _ i n t ( t e s t _ m i n w a i t , t e s t _ m a x w a i t ));
}
}
// If the d e s t i n a t i o n guid is not equal to ours , then the
// real r e q u e s t i n g node must have died b e f o r e the r e s p o n s e
// got there and the n e t w o r k r e d i r e c t e d it to us . I g n o r e .
else {
d e b u g _ p r i n t l n (" Got a B a m b o o R o u t e D e l i v e r with m i s m a t c h e d guid -- i g n o r i n g .");
}
}
// We ’ re the p r i m a r y owner , and we ’ ve been asked to store some
// data . This e n t a i l s g r a b b i n g the c u r r e n t l y s t o r e d v e r s i o n
// file , using CVS to check if there are any conflict s , and
// s t o r i n g it if not , or k i c k i n g it back if so . How I p r o c e s s
// a S t o r a g e M a n a g e r . G e t B y G U I D R e q needs to h a n d l e the bulk of
// this logic , i n c l u d i n g the i d e n t i f i c a t i o n of what m e s s a g e is
// c a l l i n g it . Yay u s e r _ d a t a .
else if ( elem . p a y l o a d i n s t a n c e o f P u t C V S R e q P a y l o a d ){
P u t C V S R e q P a y l o a d pay = ( P u t C V S R e q P a y l o a d ) elem . p a y l o a d ;
d e b u g _ d i s p _ f i l e ( pay . filename , pay . project n a me , pay . f i l e d a t a );
// D e s t i n a t i o n GUID is set e a r l i e r to the GUID of the file we want .
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new S t o r a g e M a n a g e r . G e t B y G u i d R e q ( elem . dest , true , null ,
my_sink , new P u t C V S R e q I n f o C o n t a i n e r ( pay . filename , pay . project n a m e , pay . filedata , elem . src )) , 0);
}
// We ’ re the r e q u e s t i n g node , so let ’ s see if our file
// p l a c e m e n t r e q u e s t w o r k e d out .
else if ( elem . p a y l o a d i n s t a n c e o f P u t C V S R e s p P a y l o a d ){
// If the dest guid is equal to our guid , then this must be
// a r e s p o n s e to a m e s s a g e we sent out e a r l i e r .
if ( elem . dest . e q u a l s ( m y _ g u i d )){
d e b u g _ p r i n t l n (" Got a B a m b o o R o u t e D e l i v e r with m a t c h i n g guid !");
P u t C V S R e s p P a y l o a d pay = ( P u t C V S R e s p P a y l o a d ) elem . p a y l o a d ;
if ( pay . error )
S y s t e m . err . p r i n t l n ( pay . m e s s a g e );
else {
S y s t e m . out . p r i n t l n (" Put o p e r a t i o n c o m p l e t e d s u c c e s s f u l l y ");
xx
d e b u g _ d i s p _ f i l e ( pay . f i l e n a m e + " _ v e r s i o n " , pay . project na m e ,
pay . v e r s i o n _ f i l e d a t a );
try { w r i t e _ f i l e ( pay . f i l e n a m e + " _ v e r s i o n " , pay . project n a m e ,
pay . v e r s i o n _ f i l e d a t a );}
catch ( I O E x c e p t i o n ioe ){ S y s t e m . err . p r i n t l n (" Error w r i t i n g v e r s i o n file !");}
// if we ’ re t e s t i n g
if ( a u t o m a t i c _ t e s t ){
int n e x t _ r e q u e s t _ t i m e = m a k e _ r a n d o m _ i n t ( t e s t _ m i n w a i t , t e s t _ m a x w a i t );
Date n e x t _ r e q u e s t _ d a t e = new Date ((( new Date ()). g e t T i m e ()) +
( long ) n e x t _ r e q u e s t _ t i m e );
try { a p p e n d _ t o _ l o g f i l e (" n e x t _ r e q u e s t _ d a t e :" + n e x t _ r e q u e s t _ d a t e + "\ n ");}
catch ( I O E x c e p t i o n ioe ){ S y s t e m . err . p r i n t l n (" Error a p p e n d i n g to l o g f i l e !");}
if ( n e x t _ r e q u e s t _ d a t e . b e f o r e ( s t o p D a t e )){
d e b u g _ p r i n t l n (" q u e u e i n g new R e t r i e v e T e s t D a t a A l a r m ()");
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new R e t r i e v e T e s t D a t a A l a r m () ,
n e x t _ r e q u e s t _ t i m e );
}
else {
try { a p p e n d _ t o _ l o g f i l e (" s t o p D a t e r e a c h e d . E n d i n g r e q u e s t s .\ n ");}
catch ( I O E x c e p t i o n ioe ){ S y s t e m . err . p r i n t l n (" Error a p p e n d i n g to
l o g f i l e !");}
}
}
}
}
// Otherwise , this m e s s a g e isn ’ t i n t e n d e d for us . I g n o r e !
else {
d e b u g _ p r i n t l n (" Got a B a m b o o R o u t e D e l i v e r with m i s m a t c h e d guid -- i g n o r i n g .");
}
}
// We ’ re the r e q u e s t i n g node , and the p r i m a r y owner has
// s o m e t h i n g to tell us .
else if ( elem . p a y l o a d i n s t a n c e o f S t a t u s P a y l o a d ){
S t a t u s P a y l o a d pay = ( S t a t u s P a y l o a d ) elem . p a y l o a d ;
// print it .
S y s t e m . out . p r i n t l n ( pay . msg );
}
else {
BUG (" P a y l o a d of u n k n o w n type r e t u r n e d in B a m b o o R o u t e D e l i v e r ");
}
}
p r o t e c t e d byte [] d a t a _ h a s h ( byte [] dh ) {
M e s s a g e D i g e s t md = null ;
try { md = M e s s a g e D i g e s t . g e t I n s t a n c e (" SHA "); } catch ( E x c e p t i o n e ) {}
md . u p d a t e ( dh );
r e t u r n md . d i g e s t ();
}
p r o t e c t e d byte [] m a k e _ h a s h ( S t r i n g input ){
M e s s a g e D i g e s t md = null ;
try { md = M e s s a g e D i g e s t . g e t I n s t a n c e (" SHA ");} catch ( E x c e p t i o n e ){};
md . u p d a t e ( input . g e t B y t e s ());
r e t u r n md . d i g e s t ();
}
p r o t e c t e d void w r i t e _ f i l e ( S t r i n g filename , S t r i n g project n a m e , byte [] f i l e d a t a ) t h r o w s
IOException {
// Open a file and a p p e n d , v to f i l e n a m e . We want to o v e r w r i t e w h a t e v e r a l r e a d y e x i s t s .
F i l e O u t p u t S t r e a m fos = new F i l e O u t p u t S t r e a m ( f i l e n a m e );
// write f i l e d a t a . l e n g t h bytes to f i l e s y s t e m
// TODO : Does the byte order of the s u b m i t t i n g s y s t e m make a d i f f e r e n c e here ?
Windows < - > Linux ?
fos . write ( f i l e d a t a );
// can ’ t hurt
fos . flush ();
xxi
How about
// done !
fos . close ();
}
p r o t e c t e d byte [] r e a d _ f i l e ( S t r i n g filename , S t r i n g p r o j e c t n a m e ) t h r o w s F i l e N o t F o u n d E x c e p t i o n ,
IOException {
F i l e I n p u t S t r e a m fis = new F i l e I n p u t S t r e a m ( f i l e n a m e );
// S t r i n g h a s h n a m e = p r o j e c t n a m e + ":" + f i l e n a m e ;
byte [] f i l e d a t a ;
// CVS doesn ’ t like it when I have a big block of NULL at
// the end of my files , so I have to only grab the c o n t e n t s
// of the file .
int f i l e s i z e = fis . a v a i l a b l e ();
if ( f i l e s i z e > M A X _ F I L E S I Z E ){
filesize = MAX_FILESIZE ;
}
f i l e d a t a = new byte [ f i l e s i z e ];
// read up to f i l e d a t a . size bytes into the array .
fis . read ( f i l e d a t a );
// Don ’ t need it a n y m o r e .
fis . close ();
// r e t u r n to r e q u e s t o r .
return filedata ;
}
// T e s t i n g only . Will h a n d l e the first p l a c e m e n t of data into the n e t w o r k .
/*
p r o t e c t e d void h a n d l e _ i n i t i a l _ d a t a _ a l a r m (){
try {
R u n t i m e r u n t i m e = R u n t i m e . g e t R u n t i m e ();
P r o c e s s proc = r u n t i m e . exec ("./ a p p e n d f i l e d a t a . pl " + t e s t _ f i l e n a m e );
d e b u g _ p r i n t l n (" s e n d i n g P u t C V S F i l e E v e n t ");
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new P u t C V S F i l e E v e n t ( t e s t _ f i l e n a m e , t e s t _ p r o j e c t n a m e ) , 0);
// Queue up a R e t r i e v e T e s t D a t a A l a r m
d e b u g _ p r i n t l n (" q u e u e i n g R e t r i e v e T e s t D a t a A l a r m ");
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new R e t r i e v e T e s t D a t a A l a r m () , rand . n e x t I n t ( t e s t _ m a x w a i t ));
}
catch ( I O E x c e p t i o n ioe ){
S y s t e m . out . p r i n t l n (" Error c a l l i n g a p p e n d f i l e d a t a . pl !");
}
}
*/
// T e s t i n g only . Will get data from the n e t w o r k and call a s c r i p t to
// check if it ’ s the c o r r e c t data .
p r o t e c t e d void h a n d l e _ r e t r i e v e _ t e s t _ d a t a _ a l a r m (){
d e b u g _ p r i n t l n (" s e n d i n g G e t C V S F i l e E v e n t ");
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new G e t C V S F i l e E v e n t ( t e s t _ f i l e n a m e , t e s t _ p r o j e c t n a m e ) , 0);
try {
R u n t i m e r u n t i m e = R u n t i m e . g e t R u n t i m e ();
P r o c e s s proc = r u n t i m e . exec ("./ l o g _ r e t r i e v e _ r e q u e s t . pl ");
// Note ! Must wait for these p r o c e s s e s to exit b e f o r e c o n t i n u i n g !
if ( proc . w a i t F o r () != 0){
S y s t e m . err . p r i n t l n (" Exit value = " + proc . e x i t V a l u e ());
throw new I n t e r r u p t e d E x c e p t i o n ();
}
}
catch ( I O E x c e p t i o n ioe ){
S y s t e m . out . p r i n t l n (" Error c a l l i n g l o g _ r e t r i e v e _ r e q u e s t . pl !");
}
catch ( I n t e r r u p t e d E x c e p t i o n ie ){
S y s t e m . out . p r i n t l n (" l o g _ r e t r i e v e _ r e q u e s t . pl had n o n z e r o exit s t a t u s !");
}
}
xxii
// T e s t i n g only . Will m o d i f y a s p e c i f i c file and then place the
// u p d a t e d data into the n e t w o r k .
p r o t e c t e d void h a n d l e _ s u b m i t _ t e s t _ d a t a _ a l a r m (){
try {
R u n t i m e r u n t i m e = R u n t i m e . g e t R u n t i m e ();
P r o c e s s proc = r u n t i m e . exec ("./ a p p e n d f i l e d a t a . pl " + t e s t _ f i l e n a m e );
if ( proc . w a i t F o r () != 0){
S y s t e m . err . p r i n t l n (" Exit value = " + proc . e x i t V a l u e ());
throw new I n t e r r u p t e d E x c e p t i o n ();
}
d e b u g _ p r i n t l n (" s e n d i n g P u t C V S F i l e E v e n t ");
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new P u t C V S F i l e E v e n t ( t e s t _ f i l e n a m e , t e s t _ p r o j e c t n a m e ) , 0);
/*
d e b u g _ p r i n t l n (" q u e u e i n g R e t r i e v e T e s t D a t a A l a r m ");
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new R e t r i e v e T e s t D a t a A l a r m () , rand . n e x t I n t ( t e s t _ m a x w a i t ));
*/
}
catch ( I O E x c e p t i o n ioe ){
S y s t e m . err . p r i n t l n (" Error c a l l i n g a p p e n d f i l e d a t a . pl !");
}
catch ( I n t e r r u p t e d E x c e p t i o n ie ){
S y s t e m . out . p r i n t l n (" a p p e n d f i l e d a t a . pl had n o n z e r o exit s t a t u s !");
}
}
// T e s t i n g only . Will start the test r o u t i n e s once the w a r m u p p e r i o d has ended .
p r o t e c t e d void h a n d l e _ w a r m u p _ c o m p l e t e d _ a l a r m () t h r o w s E v e n t H a n d l e r E x c e p t i o n {
try {
a p p e n d _ t o _ l o g f i l e (" W a r m u p time : " + t e s t _ w a r m u p _ t i m e + "\ n ");
a p p e n d _ t o _ l o g f i l e (" W a r m u p f i n i s h e d at : " + ( new Date ()). t o S t r i n g () + "\ n ");
}
catch ( I O E x c e p t i o n ioe ){ S y s t e m . err . p r i n t l n (" Error a p p e n d i n g to l o g f i l e !");}
// TODO : put all of this into one r o u t i n e ( r e p e a t e d code )
i n i t i a l i z e d = true ;
try { a p p e n d _ t o _ l o g f i l e (" Node p r o c e s s i n g m e s s a g e s \ n ");}
catch ( I O E x c e p t i o n ioe ){ S y s t e m . err . p r i n t l n (" Error a p p e n d i n g to l o g f i l e !");}
// Clean out the queue that may have built up .
while (! w a i t _ q . i s E m p t y ()){
h a n d l e E v e n t (( Q u e u e E l e m e n t I F ) w a i t _ q . r e m o v e F i r s t ());
}
// end r e p e a t
// Now , start the t e s t i n g .
if ( i n i t i a l _ d a t a ){
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new P u t C V S F i l e E v e n t ( t e s t _ f i l e n a m e , t e s t _ p r o j e c t n a m e ) , 0);
}
else {
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new R e t r i e v e T e s t D a t a A l a r m () , m a k e _ r a n d o m _ i n t ( t e s t _ m i n w a i t ,
t e s t _ m a x w a i t ));
}
}
p r o t e c t e d s t a t i c void d e b u g _ d i s p _ f i l e ( S t r i n g filename , S t r i n g project n a m e , byte [] f i l e d a t a ){
if ( DEBUG ){
// o u t p u t to s c r e e n
S y s t e m . out . p r i n t l n (" f i l e n a m e : " + f i l e n a m e + " p r o j e c t n a m e : " + p r o j e c t n a m e );
S y s t e m . out . p r i n t l n (" -= -= -= contents -= -= -=");
for ( int i = 0; i < f i l e d a t a . l e n g t h ; i ++){
S y s t e m . out . print (( char ) f i l e d a t a [ i ]);
}
S y s t e m . out . p r i n t l n (" -= -= -= e n d _ c o n t e n t s -= -= -=");
}
}
p r o t e c t e d s t a t i c void d e b u g _ p r i n t l n ( S t r i n g s ){
if ( DEBUG )
S y s t e m . out . p r i n t l n ( s );
}
// A p p e n d a s t a t u s m e s s a g e to the node ’ s l o g f i l e .
xxiii
p r o t e c t e d void a p p e n d _ t o _ l o g f i l e ( S t r i n g s ) t h r o w s I O E x c e p t i o n {
if ( a u t o m a t i c _ t e s t ){
F i l e O u t p u t S t r e a m fos = new F i l e O u t p u t S t r e a m ( l o g f i l e _ n a m e , true );
S t r i n g n e w S t r i n g = ( new Date ()). t o S t r i n g () + ": " + s ;
fos . write ( n e w S t r i n g . g e t B y t e s ());
fos . close ();
}
}
p r o t e c t e d B i g I n t e g e r m a k e _ s u b m i t _ h a s h n a m e ( S t r i n g filename , S t r i n g p r o j e c t n a m e ){
I n e t A d d r e s s ia = null ;
try { ia = I n e t A d d r e s s . g e t L o c a l H o s t ();}
catch ( U n k n o w n H o s t E x c e p t i o n uhe ){ BUG ( uhe );}
File i n f i l e = new File ( f i l e n a m e );
S t r i n g h o s t I P = ia . g e t H o s t A d d r e s s ();
S t r i n g a b s o l u t e P a t h = i n f i l e . g e t A b s o l u t e P a t h ();
r e t u r n m a k e _ h a s h n a m e ( filename , projectn a m e , hostIP , a b s o l u t e P a t h );
}
// TODO : C o n v e r t h a s h n a m e s to i n c l u d e the ip a d d r e s s of the node
// that s u b m i t t e d the i n i t i a l u p d a t e and the path where the file
// was i n i t i a l l y s t o r e d .
p r o t e c t e d B i g I n t e g e r m a k e _ h a s h n a m e ( S t r i n g filename , S t r i n g project na m e , S t r i n g
i n i t i a l _ i p _ a d d r e s s , S t r i n g i n i t i a l _ p a t h ){
S t r i n g h a s h n a m e = i n i t i a l _ i p _ a d d r e s s + ":" + i n i t i a l _ p a t h + ":" + p r o j e c t n a m e + ":" +
filename ;
S e c u r e H a s h s e c u r e h a s h = new S H A 1 H a s h ( d i g e s t . d i g e s t ( h a s h n a m e . g e t B y t e s ()));
B i g I n t e g e r guid = G u i d T o o l s . s e c u r e _ h a s h _ t o _ b i g _ i n t e g e r ( s e c u r e h a s h );
r e t u r n guid ;
}
p r o t e c t e d B i g I n t e g e r m a k e _ h a s h n a m e ( S t r i n g filename , S t r i n g p r o j e c t n a m e ){
S t r i n g h a s h n a m e = p r o j e c t n a m e + ":" + f i l e n a m e ;
S e c u r e H a s h s e c u r e h a s h = new S H A 1 H a s h ( d i g e s t . d i g e s t ( h a s h n a m e . g e t B y t e s ()));
B i g I n t e g e r guid = G u i d T o o l s . s e c u r e _ h a s h _ t o _ b i g _ i n t e g e r ( s e c u r e h a s h );
r e t u r n guid ;
}
p r o t e c t e d int m a k e _ r a n d o m _ i n t ( int min_int , int m a x _ i n t ){
S y s t e m . out . p r i n t l n (" m a x _ i n t : " + m a x _ i n t + " m i n _ i n t : " + m i n _ i n t + " m a x _ i n t - m i n _ i n t : "
+ ( m a x _ i n t - m i n _ i n t ));
r e t u r n m i n _ i n t + rand . n e x t I n t ( m a x _ i n t - m i n _ i n t );
}
p r o t e c t e d void i n i t G U I (){
// P r o j e c t name panel
J P a n e l panel = new J P a n e l ( new F l o w L a y o u t ( F l o w L a y o u t . LEFT ));
p r o j e c t n a m e L a b e l = new J L a b e l (" p r o j e c t : ");
p r o j e c t n a m e F i e l d = new J T e x t F i e l d (32);
panel . add ( p r o j e c t n a m e L a b e l );
panel . add ( p r o j e c t n a m e F i e l d );
// add to main pane
J P a n e l m a i n P a n e = new J P a n e l ( new B o r d e r L a y o u t ());
m a i n P a n e . add ( panel , B o r d e r L a y o u t . NORTH );
panel = new J P a n e l ( new F l o w L a y o u t ( F l o w L a y o u t . LEFT ));
f i l e n a m e L a b e l = new J L a b e l (" f i l e n a m e : ");
A c t i o n A d a p t e r b u t t o n L i s t e n e r = null ;
f i l e n a m e F i e l d = new J T e x t F i e l d (32);
s u b m i t F i l e n a m e B u t t o n = new J B u t t o n (" S u b m i t ");
b u t t o n L i s t e n e r = new A c t i o n A d a p t e r ()
{
p u b l i c void a c t i o n P e r f o r m e d ( A c t i o n E v e n t e )
{
S t r i n g filename , p r o j e c t n a m e ;
try
xxiv
{
p r o j e c t n a m e = p r o j e c t n a m e F i e l d . g e t T e x t ();
f i l e n a m e = f i l e n a m e F i e l d . g e t T e x t ();
// If we ’ re decvs - i f y i n g the file , add the
// CVS s u f f i x . -- This m e s s e s up the hash , don ’ t do it .
if ( r e t r i e v e F i l e ){
// f i l e n a m e = f i l e n a m e + " , v ";
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new G e t C V S F i l e E v e n t ( filename ,
p r o j e c t n a m e ) , 0);
// d o _ g e t ( filename , p r o j e c t n a m e );
}
else {
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new P u t C V S F i l e E v e n t ( filename ,
p r o j e c t n a m e ) , 0);
// d o _ p u t ( filename , p r o j e c t n a m e );
}
S y s t e m . out . p r i n t l n (" f i l e n a m e : " + f i l e n a m e + "\ t p r o j e c t n a m e : " +
p r o j e c t n a m e );
// F i l e n a m e S u b m i t t e d E v e n t A l a r m fsea = new
F i l e n a m e S u b m i t t e d E v e n t A l a r m ( filename , project n am e , r e t r i e v e F i l e );
// c l a s s i f i e r . d i s p a t c h is no good from here , but d i s p a t c h _ l a t e r is fine .
// c l a s s i f i e r . d i s p a t c h _ l a t e r ( fsea , 0);
}
catch ( E x c e p t i o n e2 )
{
S y s t e m . err . p r i n t l n (" e2 ");
m a i n F r a m e . r e p a i n t ();
}
}
};
s u b m i t F i l e n a m e B u t t o n . a d d A c t i o n L i s t e n e r ( b u t t o n L i s t e n e r );
s u b m i t F i l e n a m e B u t t o n . s e t M n e m o n i c ( ’ S ’);
// s u b m i t F i l e n a m e B u t t o n . s e t E n a b l e d (! a u t o m a t i c _ t e s t );
panel . add ( f i l e n a m e L a b e l );
panel . add ( f i l e n a m e F i e l d );
panel . add ( s u b m i t F i l e n a m e B u t t o n );
// add to main pane
m a i n P a n e . add ( panel , B o r d e r L a y o u t . C E N T E R );
// do the radio b u t t o n s
p u t F i l e R a d i o B u t t o n = new J R a d i o B u t t o n (" cvs - ify file " , ! r e t r i e v e F i l e );
b u t t o n L i s t e n e r = new A c t i o n A d a p t e r ()
{
p u b l i c void a c t i o n P e r f o r m e d ( A c t i o n E v e n t e )
{
r e t r i e v e F i l e = false ;
}
};
p u t F i l e R a d i o B u t t o n . a d d A c t i o n L i s t e n e r ( b u t t o n L i s t e n e r );
p u t F i l e R a d i o B u t t o n . s e t M n e m o n i c ( ’ C ’);
// p u t F i l e R a d i o B u t t o n . s e t E n a b l e d (! a u t o m a t i c _ t e s t );
g e t F i l e R a d i o B u t t o n = new J R a d i o B u t t o n (" decvs - ify file " , r e t r i e v e F i l e );
b u t t o n L i s t e n e r = new A c t i o n A d a p t e r ()
{
p u b l i c void a c t i o n P e r f o r m e d ( A c t i o n E v e n t e )
{
r e t r i e v e F i l e = true ;
}
};
g e t F i l e R a d i o B u t t o n . a d d A c t i o n L i s t e n e r ( b u t t o n L i s t e n e r );
g e t F i l e R a d i o B u t t o n . s e t M n e m o n i c ( ’ D ’);
// g e t F i l e R a d i o B u t t o n . s e t E n a b l e d (! a u t o m a t i c _ t e s t );
B u t t o n G r o u p group = new B u t t o n G r o u p ();
group . add ( p u t F i l e R a d i o B u t t o n );
xxv
group . add ( g e t F i l e R a d i o B u t t o n );
// make a new panel
panel = new J P a n e l ( new F l o w L a y o u t ( F l o w L a y o u t . RIGHT ));
// add b u t t o n s to panel
panel . add ( p u t F i l e R a d i o B u t t o n );
panel . add ( g e t F i l e R a d i o B u t t o n );
// add to the main pane again
m a i n P a n e . add ( panel , B o r d e r L a y o u t . SOUTH );
/*
m a i n P a n e . add ( n e t w o r k C h a t t e r P a n e l , B o r d e r L a y o u t . C E N T E R );
m a i n P a n e . add ( statusPa n e l , B o r d e r L a y o u t . WEST );
m a i n P a n e . add ( c o n n e c t i o n I n f o P a n e l , B o r d e r L a y o u t . SOUTH );
*/
// Set up the main frame
S t r i n g t i t l e s t r i n g = " D i s t C V S I n t e r f a c e at ";
try {
t i t l e s t r i n g += I n e t A d d r e s s . g e t L o c a l H o s t ();
}
catch ( U n k n o w n H o s t E x c e p t i o n uhe ){
t i t l e s t r i n g += " u n k n o w n host ";
}
t i t l e s t r i n g += " , guid : 0 x " + (( m y _ g u i d . t o S t r i n g ( 1 6 ) ) . s u b s t r i n g (0 ,8)). t o U p p e r C a s e ();
m a i n F r a m e = new J F r a m e ( t i t l e s t r i n g );
m a i n F r a m e . s e t D e f a u l t C l o s e O p e r a t i o n ( J F r a m e . E X I T _ O N _ C L O S E );
m a i n F r a m e . s e t C o n t e n t P a n e ( m a i n P a n e );
m a i n F r a m e . s e t S i z e ( m a i n F r a m e . g e t P r e f e r r e d S i z e ());
m a i n F r a m e . s e t L o c a t i o n (200 , 200);
m a i n F r a m e . pack ();
m a i n F r a m e . s e t V i s i b l e ( true );
}
}
xxvi
Listing 2: PrintDataStage.java
/*
* P r i n t D a t a S t a g e . java - a B a m b o o stage that d i s p l a y s the GUIDs of
* data c u r r e n t l y s t o r e d on the node .
*
* C o p y r i g h t ( C ) 2004 ,2005 A n d r e w Ian Logan
* l o g a n a @ b c . edu , a n d r e w l o g a n @ g m a i l . com
*
*/
package thesis ;
i m p o r t java . math . B i g I n t e g e r ;
i m p o r t java . nio . B y t e B u f f e r ;
i m p o r t java . s e c u r i t y . M e s s a g e D i g e s t ;
i m p o r t java . util . I t e r a t o r ;
i m p o r t java . util . R a n d o m ;
i m p o r t java . util . L i n k e d L i s t ;
import
import
import
import
o s t o r e . util . B y t e U t i l s ;
o s t o r e . util . B y t e A r r a y O u t p u t B u f f e r ;
o s t o r e . util . Pair ;
o s t o r e . util . C o u n t B u f f e r ;
import
import
import
import
seda . s a n d S t o r m . api . C o n f i g D a t a I F ;
seda . s a n d S t o r m . api . Q u e u e E l e m e n t I F ;
seda . s a n d S t o r m . api . S i n g l e T h r e a d e d E v e n t H a n d l e r I F ;
seda . s a n d S t o r m . api . S t a g e s I n i t i a l i z e d S i g n a l ;
i m p o r t b a m b o o . db . S t o r a g e M a n a g e r ;
i m p o r t b a m b o o . lss . D u s t D e v i l ;
i m p o r t b a m b o o . util . S t a n d a r d S t a g e ;
i m p o r t b a m b o o . util . G u i d T o o l s ;
i m p o r t b a m b o o . dmgr . P u t O r R e m o v e R e q ;
i m p o r t b a m b o o . dmgr . P u t O r R e m o v e R e s p ;
import
import
import
import
import
import
import
import
import
b a m b o o . dht . G a t e w a y C l i e n t ;
b a m b o o . dht . b a m b o o _ p u t _ a r g s ;
b a m b o o . dht . b a m b o o _ g e t _ a r g s ;
b a m b o o . dht . b a m b o o _ v a l u e ;
b a m b o o . dht . b a m b o o _ s e c r e t ;
b a m b o o . dht . b a m b o o _ k e y ;
b a m b o o . dht . b a m b o o _ s t a t ;
b a m b o o . dht . b a m b o o _ p l a c e m a r k ;
b a m b o o . dht . b a m b o o _ g e t _ r e s ;
i m p o r t java . awt .*;
i m p o r t java . awt . event .*;
i m p o r t javax . swing .*;
i m p o r t java . io .*;
p u b l i c class P r i n t D a t a S t a g e e x t e n d s S t a n d a r d S t a g e i m p l e m e n t s S i n g l e T h r e a d e d E v e n t H a n d l e r I F {
p r o t e c t e d b o o l e a n i n i t i a l i z e d = false ;
protected String inputFilename ;
p r o t e c t e d b o o l e a n r e t r i e v e F i l e = false ;
// C o n s t r u c t o r
p u b l i c P r i n t D a t a S t a g e () t h r o w s E x c e p t i o n {
DEBUG = false ;
e v e n t _ t y p e s = new Class []{
S t a g e s I n i t i a l i z e d S i g n a l . class ,
P r i n t D a t a A l a r m . class
};
}
// Get v a r i a b l e s from c o n f i g file , i n i t i a l i z e a n y t h i n g else
p u b l i c void init ( C o n f i g D a t a I F c o n f i g ) t h r o w s E x c e p t i o n {
super . init ( c o n f i g );
xxvii
int d e b u g _ l e v e l = c o n f i g . g e t I n t (" d e b u g _ l e v e l ");
if ( d e b u g _ l e v e l > 0)
DEBUG = true ;
}
// Event h a n d l e r
p u b l i c void h a n d l e E v e n t ( Q u e u e E l e m e n t I F item ){
if ( l o g g e r . i s D e b u g E n a b l e d ()) l o g g e r . debug (" got " + item );
if ( item i n s t a n c e o f S t a g e s I n i t i a l i z e d S i g n a l ){
d i s p a t c h ( new P r i n t D a t a A l a r m ());
}
else if ( item i n s t a n c e o f P u t O r R e m o v e R e s p ){
}
else if ( item i n s t a n c e o f P r i n t D a t a A l a r m ){
p r i n t _ d a t a ();
}
else if ( item i n s t a n c e o f S t o r a g e M a n a g e r . G e t B y T i m e R e s p ){
h a n d l e _ g e t _ b y _ t i m e _ r e s p (( S t o r a g e M a n a g e r . G e t B y T i m e R e s p ) item );
}
else if ( item i n s t a n c e o f S t o r a g e M a n a g e r . G e t B y G u i d R e s p ){
h a n d l e _ g e t _ b y _ g u i d _ r e s p (( S t o r a g e M a n a g e r . G e t B y G u i d R e s p ) item );
}
else {
throw new I l l e g a l A r g u m e n t E x c e p t i o n ( item . g e t C l a s s (). g e t N a m e ());
}
}
p r o t e c t e d s t a t i c class P r i n t D a t a A l a r m i m p l e m e n t s Q u e u e E l e m e n t I F {};
p r o t e c t e d void p r i n t _ d a t a (){
// Start with the p r i m a r y DB .
d i s p a t c h ( new S t o r a g e M a n a g e r . G e t B y T i m e R e q ( 0 , Long . MAX_VALUE , my_sink , new L i n k e d L i s t ()));
}
p r o t e c t e d void h a n d l e _ g e t _ b y _ t i m e _ r e s p ( S t o r a g e M a n a g e r . G e t B y T i m e R e s p resp ){
if ( resp . c o n t i n u a t i o n == null ){
// Also scan the r e c y c l i n g DB , since we want to make sure
// that no node is s t o r i n g t u p l e s that it shouldn ’ t be .
S t o r a g e M a n a g e r . G e t B y G u i d R e q req = new S t o r a g e M a n a g e r . G e t B y G u i d R e q ( B i g I n t e g e r . v a l u e O f
(0) , false , null , my_sink , resp . u s e r _ d a t a );
d i s p a t c h ( req );
}
else {
if ( resp . key . put ){
L i n k e d L i s t data = ( L i n k e d L i s t ) resp . u s e r _ d a t a ;
data . a d d L a s t ( new Pair ( resp . key , null /* resp . data */));
}
d i s p a t c h ( new S t o r a g e M a n a g e r . G e t B y T i m e C o n t ( resp . c o n t i n u a t i o n , my_sink ,
resp . u s e r _ d a t a ));
}
}
p r o t e c t e d void h a n d l e _ g e t _ b y _ g u i d _ r e s p ( S t o r a g e M a n a g e r . G e t B y G u i d R e s p resp ){
if ( resp . c o n t i n u a t i o n == null ){
// All done .
S y s t e m . err . p r i n t l n (" D i s t C V S S t a g e -"+ m y _ n o d e _ i d + " s t o r e d data :");
L i n k e d L i s t data = ( L i n k e d L i s t ) resp . u s e r _ d a t a ;
for ( I t e r a t o r i = data . i t e r a t o r (); i . h a s N e x t ();){
Pair p = ( Pair ) i . next ();
S t o r a g e M a n a g e r . Key k = ( S t o r a g e M a n a g e r . Key ) p . first ;
S y s t e m . err . p r i n t l n (" 0 x " + G u i d T o o l s . g u i d _ t o _ s t r i n g ( k . guid )+ " 0 x " +
B y t e U t i l s . p r i n t _ b y t e s ( k . data_has h , 0 , 4));
}
c l a s s i f i e r . d i s p a t c h _ l a t e r ( new P r i n t D a t a A l a r m () , 1 0 * 1 0 0 0 ) ;
}
else {
xxviii
if ( resp . key . put ){
L i n k e d L i s t data = ( L i n k e d L i s t ) resp . u s e r _ d a t a ;
data . a d d L a s t ( new Pair ( resp . key , resp . data ));
}
d i s p a t c h ( new S t o r a g e M a n a g e r . G e t B y G u i d C o n t ( resp . c o n t i n u a t i o n , false , my_sink ,
resp . u s e r _ d a t a ));
}
}
}
xxix
Listing 3: submithelper.pl
#!/ usr / bin / perl
# A n d r e w Logan
# 11/30/04
# W r i t t e n b e c a u s e m a k i n g a pile of s y s t e m calls in Java is a h a s s l e .
# This s c r i p t a s s u m e s that it has been given an old ( er ) cvs diff file ,
# and a newer file to be d i f f e d a g a i n s t it .
#
#
#
#
#
#
#
#
#
#
Here is what we need to do :
Make a C V S R O O T
run " cvs init " in it
make a r e p o s i t o r y d i r e c t o r y w i t h i n C V S R O O T
copy the v e r s i o n file into it
make a temp d i r e c t o r y o u t s i d e of C V S R O O T
check out a copy of the new r e p o s i t o r y
o v e r w r i t e the c h e c k e d out copy with the u p d a t e d copy
check in
copy the new v e r s i o n file back to where we s t a r t e d
$ l e n g t h = $ # ARGV + 1;
if ( $ l e n g t h < 1){
print " p l e a s e p r o v i d e an input file \ n ";
exit (1);
}
$ i n p u t f i l e = @ARGV [0];
$ c v s r o o t d i r = " c v s r o o t ";
$ c v s s u f f i x = " , v ";
$ i n p u t v e r s i o n f i l e = " $ i n p u t f i l e $ c v s s u f f i x ";
$ t e m p d i r = " t e m p d i r ";
$ m e s s a g e = " m e s s a g e ";
$ r e p o s i t o r y = " r e p o s i t o r y ";
$ r e p o s i t o r y d i r = " $ c v s r o o t d i r / $ r e p o s i t o r y ";
# where are we ?
$here = ‘ pwd ‘;
chomp ( $here );
# this is u s e f u l later
$ c v s r o o t p a t h = " $here / $ c v s r o o t d i r ";
# make the cvs root d i r e c t o r y
# mkdir (" $ c v s r o o t d i r " , 0 7 7 7 ) ;
# open the new e n t r i e s file
if ( open ( INFILE , " $ i n p u t f i l e \ _ v e r s i o n ")){
@ i n f i l e a r r a y = < INFILE >;
close ( I N F I L E );
if ( open ( OUTFILE , " > t e m p _ e n t r i e s ")){
print O U T F I L E @ i n f i l e a r r a y ;
# add f o o t e r to E n t r i e s data
print O U T F I L E " D \ n ";
close ( O U T F I L E );
}
else {
print (" can ’ t open file for o u t p u t !\ n ");
exit (1);
}
}
else {
print (" can ’ t open v e r s i o n file !\ n ");
exit (1);
}
# set up our C V S R O O T ( also makes d i r e c t o r y )
‘ cvs - d $ c v s r o o t p a t h init ‘;
# make the r e p o s i t o r y d i r e c t o r y
mkdir (" $ r e p o s i t o r y d i r " , 0 7 7 7 ) ;
# force copy v e r s i o n file there
‘ cp - f $ i n p u t v e r s i o n f i l e $ r e p o s i t o r y d i r ‘;
# make a temp d i r e c t o r y
xxx
mkdir (" $ t e m p d i r " , 0 7 7 7 ) ;
# now go to the temp d i r e c t o r y
if (!( chdir (" $ t e m p d i r "))){
print (" f a i l e d to c h a n g e d i r e c t o r y .\ n ");
c l e a n u p ();
exit (1);
}
# check out a copy of our r e p o s i t o r y
‘ cvs - d $ c v s r o o t p a t h co $reposit o r y ‘;
# go there
# now go to the temp d i r e c t o r y
if (!( chdir (" $ r e p o s i t o r y "))){
print (" f a i l e d to c h a n g e d i r e c t o r y .\ n ");
c l e a n u p (); exit (1);
}
# r e m o v e the r e c o n s t r u c t e d file
‘ rm $inputfi l e ‘;
# copy the new v e r s i o n here
‘ cp $here / $ i n p u t f i l e . ‘;
# force copy our p a r s e d E n t r i e s file over the e x i s t i n g one
‘ cp - f $here / t e m p _ e n t r i e s CVS / Entries ‘;
# check it in and r e d i r e c t S T D E R R to a log file
‘ cvs ci - m $ m e s s a g e 2 > c h e c k i n e r r o r s ‘;
# did it work ?
if ( open ( INFILE , c h e c k i n e r r o r s )){
@ i n f i l e a r r a y = < INFILE >;
close ( I N F I L E );
f o r e a c h $line ( @ i n f i l e a r r a y ){
if ( $line =~ m / c o m m i t a b o r t e d / i ){
print (" c o m m i t f a i l e d !\ n ");
# c l e a n u p ();
exit (1);
}
}
}
else {
print (" can ’ t open c h e c k i n e r r o r s .\ n ");
c l e a n u p ();
exit (1);
}
# parse the CVS / E n t r i e s file
if ( open ( INFILE , " CVS / E n t r i e s ")){
@ i n f i l e a r r a y = < INFILE >;
close ( I N F I L E );
if ( open ( OUTFILE , " > $here / $ i n p u t f i l e $ c v s s u f f i x \ _ v e r s i o n ")){
f o r e a c h $line ( @ i n f i l e a r r a y ){
if ( $line =~ $ i n p u t f i l e ){
print O U T F I L E $line ;
}
}
close ( O U T F I L E );
}
else {
print (" can ’ t open file for o u t p u t !\ n ");
exit (1);
}
}
else {
print (" can ’ t open CVS / E n t r i e s !\ n ");
exit (1);
}
# now , let ’ s go r e t r i e v e the new v e r s i o n file
if (!( chdir (" $ c v s r o o t p a t h / $ r e p o s i t o r y "))){
print (" f a i l e d to c h a n g e to r e p o s i t o r y d i r e c t o r y .\ n ");
c l e a n u p ();
exit (1);
xxxi
}
# force copy cvs ’ diff of t e s t i n p u t back to where we s t a r t e d
‘ cp - f $ i n p u t f i l e $ c v s s u f f i x $here / ‘;
# finally , d e l e t e e v e r y t h i n g to p r e v e n t old v e r s i o n s from b u i l d i n g up
if (!( chdir (" $here "))){
print (" f a i l e d to c h a n g e to s t a r t i n g d i r e c t o r y .\ n ");
c l e a n u p ();
exit (1);
}
sub c l e a n u p (){
if (!( chdir (" $here "))){
print (" f a i l e d to c h a n g e to s t a r t i n g d i r e c t o r y .\ n ");
exit (1);
}
# print " rm - rf $here / $ c v s r o o t d i r \ n ";
‘ rm - rf $here / $cvsroot d i r ‘;
# print " rm - rf $here / $ t e m p d i r \ n ";
‘ rm - rf $here / $tempdir ‘;
# ‘ rm $here / $inputfi l e ‘;
}
# done !
xxxii
Listing 4: reconstructhelper.pl
#!/ usr / bin / perl
# A n d r e w Logan
# g e t h e l p e r . pl
# 10/22/04
#
# W r i t t e n b e c a u s e m a k i n g a pile of s y s t e m calls in Java is a h a s s l e .
# This s c r i p t will r e c o n s t r u c t a CVS reposito r y , and then e x t r a c t a
# file from it . It l e a v e s < filename > in the d i r e c t o r y it was
# c a l l e d from .
#
#
#
#
#
#
Here is what we need to do :
Make a C V S R O O T
run " cvs init " in it
make a r e p o s i t o r y d i r e c t o r y in it
copy our input , v files there ( CVS only r e c o n s t r u c t s files e n d i n g in , v )
run " cvs co r e p o s i t o r y "
# TODO : it would be nice to have this file share v a r i a b l e s with
# s t o r e h e l p e r . pl , since they ’ re two h a l v e s of the same thing .
# Revision History :
# 1.3 : 1 1 / 1 9 / 0 4
# I now allow for the s c r i p t to be s t o r e d in a d i r e c t o r y s e p a r a t e from
# the one that it is being c a l l e d from .
# $Id #
$ l e n g t h = $ # ARGV + 1;
if ( $ l e n g t h == 0){
print " p l e a s e p r o v i d e an input file to r e c o n s t r u c t \ n ";
exit ();
}
$ i n p u t f i l e = @ARGV [0];
$ c v s r o o t d i r = " c v s r o o t ";
$ t e m p d i r = " t e m p d i r ";
$ r e p o s i t o r y = " r e p o s i t o r y ";
# where are we ?
$here = ‘ pwd ‘;
chomp ( $here );
# print " here : $here \ n ";
# this is u s e f u l later
$ c v s r o o t p a t h = " $here / $ c v s r o o t d i r ";
# make the cvs root d i r e c t o r y
mkdir (" $here / $ c v s r o o t d i r " , 0 7 7 7 ) ;
# set the C V S R O O T v a r i a b l e ( only for the e x e c u t i o n of the s c r i p t ).
# local $ENV { C V S R O O T } = " $ c v s r o o t p a t h ";
# a u t o m a t i c a l l y inits CVSROOT , but the - d f o r c e s it to work in
# CVS - c o n t r o l l e d d i r e c t o r i e s
‘ cvs - d $ c v s r o o t p a t h init ‘;
# move into C V S R O O T
if (!( chdir (" $ c v s r o o t p a t h "))){
print (" f a i l e d to c h a n g e to r e p o s i t o r y d i r e c t o r y .\ n ");
exit ();
}
# make the temp r e p o s i t o r y
mkdir (" $ r e p o s i t o r y " , 0 7 7 7 ) ;
# force copy the input file there
‘ cp - f $here / $ i n p u t f i l e $ r e p o s i t o r y / $inputf il e ‘;
# now go back to where we s t a r t e d
if (!( chdir (" $here "))){
print (" f a i l e d to c h a n g e d i r e c t o r y .\ n ");
exit ();
}
xxxiii
# check out the r e p o s i t o r y
‘ cvs - d $ c v s r o o t p a t h co $reposi t o r y ‘;
# now , let ’ s go r e t r i e v e the file
if (!( chdir (" $here / $ r e p o s i t o r y "))){
print (" f a i l e d to c h a n g e to r e p o s i t o r y d i r e c t o r y .\ n ");
exit ();
}
# copy the u n d i f f e d file ( s ) back to where we s t a r t e d
# FIXME : this won ’ t h a n d l e s u b d i r e c t o r i e s .
@ f i l e n a m e s = ‘ ls ‘;
f o r e a c h $ f i l e n a m e ( @ f i l e n a m e s ){
# i g n o r e the CVS director y , the rest s h o u l d be s o u r c e files . This
# is a bit of a hack , since it ’ s a c t u a l l y just m a t c h i n g files with
#" CVS " at the end of their names . For now , this is not a big
# deal . It will , however , copy e v e r y t h i n g back on every run . I
# s h o u l d fix that .
if (!( $ f i l e n a m e =~ / CVS$ /)){
open ( infile , " $ f i l e n a m e ");
open ( outfile , " > $here / $ f i l e n a m e ");
@ i n f i l e l i n e s = < infile >;
close ( i n f i l e );
f o r e a c h $line ( @ i n f i l e l i n e s ){
print o u t f i l e $line ;
}
close ( o u t f i l e );
}
}
# I ’ m not w o r r y i n g about c l e a n i n g up the director i e s , since it ’ s
# p r o b a b l y f a s t e r to not have to c r e a t e them all the time .
# done !
xxxiv
8
Appendix B: Test Scripts
Listing 5: go big
#!/ usr / bin / perl
#
#
#
#
go_big
A n d r e w Logan
l o g a n a @ b c . edu , a n d r e w l o g a n @ g m a i l . com
3/14/05
# W r i t t e n to a u t o m a t e the p r o c e s s of doing m u l t i p l e tests of the
# DistCVS system .
$ h o s t n a m e = ‘ hostname ‘;
chomp ( $ h o s t n a m e );
$ s t a r t _ e x p e r i m e n t = 15;
$ e n d _ e x p e r i m e n t = 15;
for ( $i = $ s t a r t _ e x p e r i m e n t ; $i < $ e n d _ e x p e r i m e n t +1; $i ++){
if ( $i > $ s t a r t _ e x p e r i m e n t ){
print " * * * * * W A I T I N G TO BEGIN E X P E R I M E N T $i * * * * * \ n ";
sleep (10 * 60);
}
print " * * * * * B E G I N N I N G E X P E R I M E N T $i * * * * * \ n ";
# clear the old r e s u l t s
if ( $ h o s t n a m e eq ’ cslabgw1 ’){
s y s t e m "./ s e t u p _ t e s t . sh ";
}
else {
# d e l e t i n g a pile of d i r e c t o r i e s also takes some a m o u n t of
# time ... and it ’ s _BAD_ to start again b e f o r e this has
# f i n i s h e d . Wait until m a s t e r _ f o o 1 is gone to p r o c e e d . This
# also helps s y n c h r o n i z e the rest of the nodes to the g a t e w a y .
# I think it is u n l i k e l y that we will o v e r s h o o t this p e r i o d and
# catch the c r e a t i o n of the next one .
$ m a s t e r _ f o o 1 _ s t a t u s = ‘ find - iname master_f o o 1 ‘;
chomp ( $ m a s t e r _ f o o 1 _ s t a t u s );
while ( $ m a s t e r _ f o o 1 _ s t a t u s eq ’./ master_f o o 1 ’){
print " m a s t e r _ f o o 1 e x i s t s \ n ";
sleep (1);
# check every s e c o n d
$ m a s t e r _ f o o 1 _ s t a t u s = ‘ find - iname master_f o o 1 ‘;
chomp ( $ m a s t e r _ f o o 1 _ s t a t u s );
}
}
# start the c o r r e c t test
$ c o m m a n d _ l i n e = "./ go_$i ";
system $command_line ;
# generate results
$ c o m m a n d _ l i n e = "./ m a k e _ g l o b a l _ e x p e r i m e n t _ s t a t s . pl > t e s t _ $ i \ _ r e s u l t s ";
system $command_line ;
# store e v e r y t h i n g for f u t u r e r e f e r e n c e
if ( $ h o s t n a m e eq ’ cslabgw1 ’){
$ c o m m a n d _ l i n e = " tar cvf a u t o _ e x p e r i m e n t _ $ i \ _data . tar cslab * \ : * / " ;
system $command_line ;
}
}
print " * * * * * A U T O M A T I C E X P E R I M E N T S C O M P L E T E * * * * * * \ n ";
# e - mail !
# ‘./ p r o c e s s _ a n d _ s e n d _ r e s u l t s . pl ‘;
xxxv
Listing 6: go
#!/ bin / bash
# go
# A n d r e w Logan
# l o g a n a @ b c . edu , a n d r e w l o g a n @ g m a i l . com
# S t a r t s a s i n g l e test of the B a m b o o s y s t e m .
./ r u n _ l o c a l _ n o d e s . pl - nodes =10 - w i t h _ u p d a t e r - w i t h _ g a t e w a y
xxxvi
Listing 7: run local nodes.pl
#!/ usr / bin / perl
#
#
#
#
r u n _ l o c a l _ n o d e s . pl
A n d r e w Logan
l o g a n a @ b c . edu , a n d r e w l o g a n @ g m a i l . com
12/6/04
#
#
#
#
#
#
#
This s c r i p t will start a s p e c i f i e d n u m b e r of b a m b o o nodes on a local
m a c h i n e ( with or w i t h o u t a g a t e w a y ) , wait some a m o u n t of time for
t h i n g s to s e t t l e down , and then start c h u r n i n g the n e t w o r k ( k i l l i n g
nodes and then r e s t a r t i n g them after a r a n d o m a m o u n t of time ). This
s c r i p t keeps track of the c u r r e n t pids of the c l i e n t processes , and
also keeps track of the c u r r e n t l y a s s i g n e d port n u m b e r s to p r e v e n t
conflicts .
use G e t o p t :: Long ;
# init r a n d o m n u m b e r g e n e r a t o r
srand ();
# get n u m b e r of nodes to run .
& G e t O p t i o n s (" nodes = i "
" with_gateway "
" with_updater "
" with_initial_data "
" cfgfile =s"
" kill_percent =f"
" no_warmup "
" no_run_time "
=>
=>
=>
=>
=>
=>
=>
=>
\ $num_no de s ,
\ $with_gateway ,
\ $with_updater ,
\ $with_initial_data ,
\ $cfg_filename ,
\ $kill_percent ,
\ $no_war mu p ,
\ $ n o _ r u n _ t i m e );
if ( not d e f i n e d $ n u m _ n o d e s ){
print " @ARGS [0] - nodes = < int > [ - w i t h _ g a t e w a y ] [ - w i t h _ u p d a t e r ]\ n ";
exit ;
}
if ( d e f i n e d $ c f g _ f i l e n a m e ){
$ c f g _ f l a g = " - c f g f i l e $ c f g _ f i l e n a m e ";
}
if ( not d e f i n e d $ k i l l _ p e r c e n t ){
$ k i l l _ p e r c e n t = .2;
}
print " * * * * * c f g _ f l a g : $ c f g _ f l a g ****\ n ";
$ h o s t n a m e = ‘ hostname ‘;
chomp ( $ h o s t n a m e );
$port = 2 0 0 0 0 ;
$ g a t e w a y p o r t = $port ;
$updaterport = $gatewayport ;
$ l i v e n o d e s = 0;
$ d e a d n o d e s = 0;
$ l o g f i l e = " $ h o s t n a m e : $ l i v e p o r t / d i f f _ r e s u l t s . log ";
if ( $ w i t h _ u p d a t e r ){
$ u p d a t e r = " - u p d a t e r ";
}
if ( $ w i t h _ i n i t i a l _ d a t a ){
$ i n i t i a l _ d a t a = " - i n i t i a l _ d a t a ";
}
$ b e f o r e _ k i l l e d _ r u n t i m e = 20 * 60;
$ a f t e r _ k i l l e d _ r u n t i m e = 20 * 60;
$ a f t e r _ r a i s e d _ r u n t i m e = 20 * 60;
# s e c o n d s to sleep b e f o r e b e g i n n i n g e x p e r i m e n t run .
$ s t a b i l i z e _ t i m e = 5 * 60;
# $ s t a b i l i z e _ t i m e = 0;
# Java is e x p e c t i n g this in m i l l i s e c o n d s
$experiment_runtime = ( $before_killed_runtime + $after_killed_runtime + $after_raised_runtime ) *
1000;
# give me time to seed data into the n e t w o r k
xxxvii
# $ g a t e w a y _ p a u s e = 1 * 60;
$ g a t e w a y _ p a u s e = 15;
# $ g a t e w a y _ p a u s e = 0;
# $ i n t e r _ n o d e _ p a u s e = 30;
$ i n t e r _ n o d e _ p a u s e = 15;
# $ i n t e r _ n o d e _ p a u s e = 0;
# in s e c o n d s
$ k i l l n o d e _ s l e e p _ i n t e r v a l = 10;
$ k i l l n o d e _ s l e e p _ i n t e r v a l = 10;
# m a x i m u m a m o u n t of time to sleep b e t w e e n o p e r a t i o n a t t e m p t s ( s e c o n d s );
# TODO : take this into a c c o u n t with the node t i m i n g
$ m a x _ s l e e p _ t i m e = 1 * 60;
# $ m a x _ s l e e p _ t i m e = 5;
# random max_sleep_time ?
$ r a n d o m _ s l e e p = 0;
# a m o u n t of time after the e x p e r i m e n t run ends to allow all of the m e s s a g e s in the s y s t e m to be
dealt with . ( in s e c o n d s )
$ c o o l d o w n _ t i m e = 2 * 60;
# only d i s p l a y the GUI for c s l a b g w 1 : 2 0 0 0 0 ( g a t e w a y where the data is s e e d e d )
$ o n l y _ d i s p l a y _ e s s e n t i a l _ g u i = true ;
# A u t o m a t i c D a t a S u b m i s s i o n H a c k ! C a u s e s the g a t e w a y on c s l a b g w 1 to
# a u t o m a t i c a l l y s u b m i t foo1 / foo1 into the n e t w o r k . This gets rid of
# the last GUI , and a l l o w s t e s t i n g to be e n t i r e l y a u t o n o m o u s .
# $adsh = true ;
if ( $ o n l y _ d i s p l a y _ e s s e n t i a l _ g u i ){
$gui = " - nogui ";
}
@pidlist ;
@liveportlist ;
@deadportlist ;
# init d e a d p o r t l i s t
for ( $i = 0; $i < $ n u m _ n o d e s ; $i ++){
$ d e a d p o r t l i s t [ $i ] = -1;
}
# start the g a t e w a y node if we want one ( as an u p d a t e r if we want that too )
if ( $ w i t h _ g a t e w a y ){
$pid = fork ();
# are we the child p r o c e s s ?
if ( $pid == 0){
my $date = ‘ date ‘;
chomp ( $date );
my $ h o s t n a m e = ‘ hostname ‘;
chomp ( $ h o s t n a m e );
if ( $ o n l y _ d i s p l a y _ e s s e n t i a l _ g u i && ( $ h o s t n a m e eq ’ cslabgw1 ’) && !( $adsh )){
$gui = "";
}
# make c s l a b g w 1 a u t o m a t i c a l l y s u b m i t data into the n e t w o r k .
a p p r o p r i a t e to do so as the n e t w o r k is c o m i n g up .
if ( $adsh && ( $ h o s t n a m e eq ’ cslabgw1 ’)){
$ a d s h _ f l a g = " - adsh ";
}
Note that it is only
print "**** GUI : $gui ****\ n ";
# Java is e x p e c t i n g this in m i l l i s e c o n d s
if ( not d e f i n e d $ n o _ w a r m u p ){
$ t e s t _ w a r m u p _ t i m e = ((( $ n u m _ n o d e s - 2) * $ i n t e r _ n o d e _ p a u s e ) + $ g a t e w a y _ p a u s e ) * 1000;
}
if ( not d e f i n e d $ n o _ r u n _ t i m e ){
$test_run_time = $experiment_runtime + $test_warmup_time + $stabilize_time ;
}
& i n i t _ l o g _ f i l e ( $port );
& l o g _ t o _ l i v e _ n o d e s ( " \ " \ # node : $ h o s t n a m e : $port o n l i n e at $date \"");
xxxviii
print " child g a t e w a y with port : $port \ n ";
exec ("./ p a r s e _ c f g _ a n d _ r u n . pl $ c f g _ f l a g - port = $port - g a t e w a y $ u p d a t e r $ i n i t i a l _ d a t a
- w a r m u p _ t i m e = $ t e s t _ w a r m u p _ t i m e - r u n _ t i m e = $ t e s t _ r u n _ t i m e $gui $ a d s h _ f l a g &");
exit ;
}
# we ’ re the p a r e n t
else {
@ l i v e p o r t l i s t [ $ l i v e n o d e s ] = $port ;
$ l i v e n o d e s ++;
$port +=2;
print " p a r e n t : s l e e p i n g to allow g a t e w a y to e s t a b l i s h i t s e l f \ n ";
sleep ( $ g a t e w a y _ p a u s e );
print " p a r e n t : awake after g a t e w a y sleep \ n ";
}
}
else {
# sleep to let me seed the n e t w o r k
sleep ( $ g a t e w a y _ p a u s e );
}
for ( $i = $ l i v e n o d e s ; $i < $ n u m _ n o d e s ; $i ++){
my $pid = fork ();
# if child :
if ( $pid == 0){
my $date = ‘ date ‘;
chomp ( $date );
# Java is e x p e c t i n g this in m i l l i s e c o n d s
if ( not d e f i n e d $ n o _ w a r m u p ){
$ t e s t _ w a r m u p _ t i m e = (( $ n u m _ n o d e s - $i - 1) * $ i n t e r _ n o d e _ p a u s e ) * 1000;
}
if ( not d e f i n e d $ n o _ r u n _ t i m e ){
$test_run_time = $experiment_runtime + $test_warmup_time + $stabilize_time ;
}
if ( $port == $ u p d a t e r p o r t ){
& i n i t _ l o g _ f i l e ( $port );
& l o g _ t o _ l i v e _ n o d e s ( " \ " \ # node : $ h o s t n a m e : $port o n l i n e at $date \"");
print " child u p d a t e r with port : $port \ n ";
exec ("./ p a r s e _ c f g _ a n d _ r u n . pl $ c f g _ f l a g - port = $port $ u p d a t e r $ i n i t i a l _ d a t a
- w a r m u p _ t i m e = $ t e s t _ w a r m u p _ t i m e - r u n _ t i m e = $ t e s t _ r u n _ t i m e $gui &");
}
else {
# Java is e x p e c t i n g this in m i l l i s e c o n d s
# $ t e s t _ w a r m u p _ t i m e = ((( $ n u m _ n o d e s - $i - 1) * $ i n t e r _ n o d e _ p a u s e ) + $ s t a b i l i z e _ t i m e ) *
1000;
# $test_run_time = $experiment_runtime + $test_warmup_time ;
& i n i t _ l o g _ f i l e ( $port );
& l o g _ t o _ l i v e _ n o d e s ( " \ " \ # node : $ h o s t n a m e : $port o n l i n e at $date \"");
print " child node with port : $port \ n ";
exec ("./ p a r s e _ c f g _ a n d _ r u n . pl $ c f g _ f l a g - port = $port - w a r m u p _ t i m e = $ t e s t _ w a r m u p _ t i m e
- r u n _ t i m e = $ t e s t _ r u n _ t i m e $gui &");
}
exit ;
}
# if p a r e n t
else {
@ l i v e p o r t l i s t [ $ l i v e n o d e s ] = $port ;
$ l i v e n o d e s ++;
$port +=2;
sleep ( $ i n t e r _ n o d e _ p a u s e );
}
}
# Note ! Array l e n g t h s in perl are one less than the c o n v e n t i o n a l idea of l e n g t h .
print " p i d l i s t : @ p i d l i s t \ n l e n g t h : $ # p i d l i s t \ n ";
print " l i v e p o r t l i s t : @ l i v e p o r t l i s t \ n l e n g t h : $ # l i v e p o r t l i s t \ n ";
print " d e a d p o r t l i s t : @ d e a d p o r t l i s t \ n l e n g t h : $ # d e a d p o r t l i s t \ n ";
# i n i t i a l sleep to s t a b i l i z e n e t w o r k
$date = ‘ date ‘;
chomp ( $date );
& l o g _ t o _ l i v e _ n o d e s ( " \ " \ # s l e e p i n g for $ s t a b i l i z e _ t i m e s e c o n d s to s t a b i l i z e n e t w o r k b e g i n n i n g at
$date \"");
print " p a r e n t : s l e e p i n g to s t a b i l i z e n e t w o r k \ n ";
sleep ( $ s t a b i l i z e _ t i m e );
print " p a r e n t : awake - b e g i n n i n g e x p e r i m e n t \ n ";
xxxix
sleep ( $ b e f o r e _ k i l l e d _ r u n t i m e );
print " p a r e n t : awake - b e g i n n i n g n e t w o r k churn \ n ";
# not perfect , but will cut off all of the b e g i n n i n g data .
# print " r e s e t t i n g s t a t i s t i c s \ n ";
#& c l e a n _ s l a t e ;
$date = ‘ date ‘;
chomp ( $date );
& l o g _ t o _ l i v e _ n o d e s ( " \ " \ # n e t w o r k churn b e g i n n i n g at $date \"");
# in s e c o n d s
$ t i m e s l e p t = 0;
$ r a i s e _ n o d e s = false ;
$ t i m e _ t o _ s l e e p = rand ( $ m a x _ s l e e p _ t i m e );
print " p a r e n t : going to sleep \ n ";
# sleep for some a m o u n t of time so all nodes don ’ t die at once .
sleep ( $ t i m e _ t o _ s l e e p );
print " p a r e n t : awake \ n ";
# kill 20% by d e f a u l t
for ( $i = 0; $i < $ k i l l _ p e r c e n t * $ n u m _ n o d e s ; $i ++){
print " p a r e n t : c a l l i n g k i l l n o d e \ n ";
& killnode ;
sleep ( $ k i l l n o d e _ s l e e p _ i n t e r v a l ); # wait a l i t t l e bit b e f o r e doing it again .
}
print " p a r e n t : going to sleep \ n ";
# sleep for $ m a x _ s l e e p _ t i m e - $ t i m e _ t o _ s l e e p to e n s u r e that all s c r i p t s end at r o u g h l y the same time
sleep ( $ m a x _ s l e e p _ t i m e - $ t i m e _ t o _ s l e e p );
# see how the n e t w o r k r e a c t s now .
sleep ( $ a f t e r _ k i l l e d _ r u n t i m e );
print " p a r e n t : awake \ n ";
if ( $ r a i s e _ n o d e s ){
# raise the nodes we k i l l e d above
for ( $i = 0; $i < $ k i l l _ p e r c e n t * $ n u m _ n o d e s ; $i ++){
print " p a r e n t : c a l l i n g r e s u r r e c t n o d e \ n ";
& r e s u r r e c t n o d e ((( $ k i l l _ p e r c e n t * $ n u m _ n o d e s ) - $i )* $ r e s u r r e c t n o d e _ s l e e p _ i n t e r v a l );
sleep ( $ r e s u r r e c t n o d e _ s l e e p _ i n t e r v a l ); # wait a l i t t l e bit b e f o r e doing it again .
}
print " p a r e n t : going to sleep \ n ";
# see if the n e t w o r k can f i g u r e t h i n g s out again .
sleep ( $ a f t e r _ r a i s e d _ r u n t i m e );
print " p a r e n t : awake \ n ";
}
print " p a r e n t : c o o l i n g down e x p e r i m e n t \ n ";
sleep ( $ c o o l d o w n _ t i m e );
print " p a r e n t : t e r m i n a t i n g e x p e r i m e n t \ n ";
# d r a s t i c but quick .
‘ k i l l a l l java ‘;
$date = ‘ date ‘;
chomp ( $date );
& l o g _ t o _ l i v e _ n o d e s ( " \ " \ # local e x p e r i m e n t t e r m i n a t e d at $date \"");
# while ( $ t i m e s l e p t < $ r u n t i m e ){
#
# pick a r a n d o m i n t e r v a l to sleep ?
#
if ( $ r a n d o m _ s l e e p ){
#
$ t i m e _ t o _ s l e e p = rand ( $ m a x _ s l e e p _ t i m e );
#
}
#
else {
#
$time_to_sleep = $max_sleep_time ;
#
}
#
$ t i m e s l e p t += $ t i m e _ t o _ s l e e p ;
#
print " p a r e n t : going to sleep \ n ";
#
# sleep for some a m o u n t of time to make the n e t w o r k s t a b l e .
#
sleep ( $ t i m e _ t o _ s l e e p );
#
print " p a r e n t : awake \ n ";
xl
#
#
#
#
#
#
#
#
#
#
#
#
#}
# flip a w e i g h t e d coin to kill node
if ( rand (1) < 1){
for ( $i = 0; $i < 2; $i ++){
print " p a r e n t : c a l l i n g k i l l n o d e \ n ";
& killnode ;
}
# flip a w e i g h t e d coin to r e s u r r e c t node
if ( rand (1) < 0){
print " p a r e n t : c a l l i n g r e s u r r e c t n o d e \ n ";
& resurrectnode ;
}
sub k i l l n o d e {
print " live nodes : $ l i v e n o d e s \ n ";
# are there any nodes to kill ?
if ( $ l i v e n o d e s <= 0){
print " r e t u r n i n g to p a r e n t \ n ";
return ;
}
# -1 ( in this case ) is my s i g n a l that the node is a l r e a d y alive
do {
$ n o d e _ t o _ k i l l = rand @ l i v e p o r t l i s t ;
} while ( $ l i v e p o r t l i s t [ $ n o d e _ t o _ k i l l ] == -1);
@ o u t p u t = ‘ ps aux | grep java | grep $hostname - $ l i v e p o r t l i s t [ $ n o d e _ t o _ k i l l ] ‘;
$ j a v a _ p i d _ l i n e = @ o u t p u t [0];
# print " j a v a _ p i d _ l i n e : $ j a v a _ p i d _ l i n e \ n ";
# print " o u t p u t : @ o u t p u t ";
# I want the s e c o n d e l e m e n t in this space - d e l i m i t e d s t r i n g .
@ t e m p a r r a y = split ( ’ ’, $ j a v a _ p i d _ l i n e );
$ j a v a _ p i d = @ t e m p a r r a y [1];
print " p a r e n t : k i l l i n g node \ n ";
# kill the t a r g e t e d node
‘ kill $java_pid ‘;
my $date = ‘ date ‘;
chomp $date ;
& l o g _ t o _ n o d e ( " \ " \ # node k i l l e d : $date \"" , $ l i v e p o r t l i s t [ $ n o d e _ t o _ k i l l ]);
& l o g _ t o _ l i v e _ n o d e s ( " \ " \ # node : $ h o s t n a m e : $ l i v e p o r t l i s t [ $ n o d e _ t o _ k i l l ] k i l l e d at $date \"");
$livenod e s - -;
$ d e a d n o d e s ++;
# move the port n u m b e r to the i n a c t i v e list
@ d e a d p o r t l i s t [ $ n o d e _ t o _ k i l l ] = @ l i v e p o r t l i s t [ $ n o d e _ t o _ k i l l ];
@ l i v e p o r t l i s t [ $ n o d e _ t o _ k i l l ] = -1;
print " l i v e p o r t l i s t : @ l i v e p o r t l i s t \ n ";
print " d e a d p o r t l i s t : @ d e a d p o r t l i s t \ n ";
return ;
}
sub r e s u r r e c t n o d e {
$ r e s u r r e c t n o d e _ r e m a i n i n g _ s l e e p _ i n t e r v a l = $_ [0];
print " dead nodes : $ d e a d n o d e s \ n ";
# are there any dead nodes ?
if ( $ d e a d n o d e s <= 0){
print " r e t u r n i n g to p a r e n t \ n ";
return ;
}
# -1 is my s i g n a l that the node is a l r e a d y dead
do {
$ n o d e _ t o _ r e s = rand @ d e a d p o r t l i s t ;
} while ( @ d e a d p o r t l i s t [ $ n o d e _ t o _ r e s ] == -1);
$ r e s u r r e c t _ p o r t = @ d e a d p o r t l i s t [ $ n o d e _ t o _ r e s ];
# r e s t a r t node
# TODO : f i g u r e out g a t e w a y i s s u e s
xli
print " p a r e n t : r e s u r r e c t i n g node \ n ";
my $pid = fork ();
if ( $pid == 0){
my $date = ‘ date ‘;
chomp $date ;
& l o g _ t o _ n o d e ( " \ " \ # node r e s u r r e c t e d : $date \"" , $ r e s u r r e c t _ p o r t );
& l o g _ t o _ l i v e _ n o d e s ( " \ " \ # node : $ h o s t n a m e : $ r e s u r r e c t _ p o r t r e s u r r e c t e d at $date \"");
# TODO : is this a good idea ?
# TODO : you never r e t u r n from an exec ().
# TODO : add in some more d e l a y s here ?
if ( not d e f i n e d $ n o _ r u n _ t i m e ){
$test_run_time = $after_raised_runtime + $resurrectnode_remaining_sleep_interval ;
}
if ( $ w i t h _ g a t e w a y && ( $ r e s u r r e c t _ p o r t == $ g a t e w a y p o r t )){
exec ("./ p a r s e _ c f g _ a n d _ r u n . pl $ c f g _ f l a g - port = $ r e s u r r e c t _ p o r t - g a t e w a y $ u p d a t e r
- r u n _ t i m e = $ t e s t _ r u n _ t i m e $gui &");
print " s t a r t i n g g a t e w a y ";
} elsif ( $ w i t h _ u p d a t e r && ( $ r e s u r r e c t _ p o r t == $ u p d a t e r p o r t )){
exec ("./ p a r s e _ c f g _ a n d _ r u n . pl $ c f g _ f l a g - port = $ r e s u r r e c t _ p o r t $ u p d a t e r
- r u n _ t i m e = $ t e s t _ r u n _ t i m e $gui &");
print " s t a r t i n g u p d a t e r ";
} else {
exec ("./ p a r s e _ c f g _ a n d _ r u n . pl $ c f g _ f l a g - port = $ r e s u r r e c t _ p o r t - r u n _ t i m e = $ t e s t _ r u n _ t i m e
$gui &");
print " s t a r t i n g child ";
}
print " with port : $ r e s u r r e c t _ p o r t \ n ";
exit ;
}
# if p a r e n t
else {
$ l i v e n o d e s ++;
$deadnod e s - -;
# move the port n u m b e r to the a c t i v e list
@ l i v e p o r t l i s t [ $ n o d e _ t o _ r e s ] = @ d e a d p o r t l i s t [ $ n o d e _ t o _ r e s ];
@ d e a d p o r t l i s t [ $ n o d e _ t o _ r e s ] = -1;
print " l i v e p o r t l i s t : @ l i v e p o r t l i s t \ n ";
print " d e a d p o r t l i s t : @ d e a d p o r t l i s t \ n ";
return ;
}
}
# r e m o v e a c c u m u l a t e d s t a t i s t i c s i n f o r m a t i o n from b e f o r e the churn began .
sub c l e a n _ s l a t e {
f o r e a c h $ l i v e p o r t ( @ l i v e p o r t l i s t ){
& i n i t _ l o g _ f i l e ( $ l i v e p o r t );
& l o g _ t o _ n o d e ( " \ " \ # churn b e g i n n i n g \ n \"" , $ l i v e p o r t );
# kill the s t a r t u p parts
# ‘ rm - rf $ h o s t n a m e : $ l i v e p o r t / d i f f _ r e s u l t s . log ‘;
# tag the new one
# ‘ echo $ h o s t n a m e : $ l i v e p o r t : * begin churn * m a x _ s l e e p _ t i m e : $ m a x _ s l e e p _ t i m e r a n d o m _ s l e e p :
$ r a n d o m _ s l e e p n u m _ n o d e s : $ n u m _ n o d e s >> $logfile ‘;
}
}
sub i n i t _ l o g _ f i l e {
my ( $ p o r t n u m ) = @_ ;
my $date = ‘ date ‘;
chomp ( $date );
my $ f i l e h e a d e r = "\"\# $ h o s t n a m e : $ p o r t n u m : m a x _ s l e e p _ t i m e : $ m a x _ s l e e p _ t i m e r a n d o m _ s l e e p :
$random_sleep num_nodes : $num_nodes test_warmup_time : $test_warmup_time test_run_time :
$ t e s t _ r u n _ t i m e now : $date \"";
# print $ f i l e h e a d e r ;
‘ rm - rf $ h o s t n a m e : $ p o r t n u m / d i f f _ r e s u l t s . log ‘;
# print " echo $ f i l e h e a d e r > $ h o s t n a m e : $ p o r t n u m / d i f f _ r e s u l t s . log \ n ";
‘ echo $ f i l e h e a d e r > $ h o s t n a m e : $ p o r t n u m / d i f f _ r e s u l t s . log \ n ‘;
}
sub l o g _ t o _ l i v e _ n o d e s {
my ( $ m e s s a g e ) = @_ ;
f o r e a c h $ l i v e p o r t ( @ l i v e p o r t l i s t ){
xlii
if ( $ l i v e p o r t != -1){
# ‘ echo $ m e s s a g e >> $ h o s t n a m e : $ l i v e p o r t / d i f f _ r e s u l t s . log ‘;
l o g _ t o _ n o d e ( $message , $ l i v e p o r t );
}
}
}
sub l o g _ t o _ n o d e {
my ( $message , $ p o r t n u m ) = @_ ;
# print " l o g _ t o _ n o d e : m e s s a g e : $ m e s s a g e p o r t n u m : $ p o r t n u m \ n ";
‘ echo $ m e s s a g e >> $ h o s t n a m e : $ p o r t n u m / d i f f _ r e s u l t s . log ‘;
}
xliii
Listing 8: parse cfg and run.pl
#!/ usr / bin / perl
#
#
#
#
p a r s e _ c f g _ a n d _ r u n . pl
A n d r e w Logan
l o g a n a @ b c . edu , a n d r e w l o g a n @ g m a i l . com
12/6/04
#
#
#
#
This perl s c r i p t will parse t h r o u g h a B a m b o o c o n f i g u r a t i o n file ,
r e p l a c e the v a r i a b l e s w i t h i n with the c o r r e c t informat i o n , and then
start a node using that file . Based off of location - test - menu . pl ,
found in the b a m b o o d i s t r i b u t i o n .
use G e t o p t :: Long ;
# get port to run node on , doesn ’ t count
$ r e s u l t = G e t O p t i o n s (" c f g f i l e = s "
=>
" port = i "
=>
" gateway "
=>
" to_put =i"
=>
" updater "
=>
" put_size =i"
=>
" initial_data " =>
" warmup_time =i" =>
" run_time =i"
=>
" nogui "
=>
" adsh "
=>
when r u n n i n g a g a t e w a y node
\ $cfginfi l e ,
\ $port ,
\ $is_gat e w a y ,
\ $to_put ,
\ $is_upd a t e r ,
\ $put_size ,
\ $does_initial_data ,
\ $warmup_time ,
\ $run_time ,
\ $hide_gui ,
\ $ d o _ a d s h );
if ( not d e f i n e d $port ){
print " usage : p a r s e _ c f g _ a n d _ r u n . pl [ - c f g f i l e < filename >] - port < port > [ - g a t e w a y ] [ - t o _ p u t
< to_put >] [ - p u t _ s i z e < put_size >] [ i n i t i a l _ d a t a ] [ w a r m u p _ t i m e < warmup >] [ r u n _ t i m e < run >]\ n ";
exit ;
}
# defaults
if ( not d e f i n e d $ c f g i n f i l e ){
$ c f g i n f i l e = " base . cfg ";
}
$ g a t e w a y _ p o r t = $port ;
$ h o s t n a m e = ‘ hostname ‘;
chomp ( $ h o s t n a m e );
# r e m o v e t r a i l i n g n e w l i n e from ‘ hostname ‘
# TODO : Make this more g e n e r a l .
if ( $ i s _ g a t e w a y ){
$ g a t e w a y = " $ h o s t n a m e : $ g a t e w a y _ p o r t ";
$ g a t e w a y _ c o u n t = -1;
}
else {
$gateway = " $hostname :20000";
$ g a t e w a y _ c o u n t = 11;
}
if ( $ i s _ u p d a t e r ){
$ u p d a t e r _ v a r = " true ";
}
else {
$ u p d a t e r _ v a r = " false ";
}
if ( $ d o e s _ i n i t i a l _ d a t a ){
$ i n i t i a l _ d a t a _ v a r = " true ";
}
else {
$ i n i t i a l _ d a t a _ v a r = " false ";
}
if ( not d e f i n e d $ t o _ p u t ){
$ t o _ p u t = -1;
}
if ( not d e f i n e d $ p u t _ s i z e ){
$ p u t _ s i z e = -1;
}
xliv
if ( $ h i d e _ g u i ){
$ s h o w _ g u i _ v a r = false ;
}
else {
$ s h o w _ g u i _ v a r = true ;
}
if ( $ d o _ a d s h ){
$ a u t o m a t i c _ d a t a _ s u b m i s s i o n _ h a c k = true ;
}
else {
$ a u t o m a t i c _ d a t a _ s u b m i s s i o n _ h a c k = false ;
}
$ d a t a _ m a n a g e r _ d e b u g _ l e v e l = 1;
$ d i r n a m e = " $ h o s t n a m e : $port ";
mkdir ( $ d i r n a m e );
$ f i l e n a m e _ p r e f i x = " $hostnam e - $port ";
my $cfg = " $ d i r n a m e / $ f i l e n a m e _ p r e f i x . cfg ";
my $log = " $ d i r n a m e / $ f i l e n a m e _ p r e f i x . log ";
my $ b l o c k s d i r = " $ d i r n a m e / $ f i l e n a m e _ p r e f i x - b l o c k s ";
# print " S t a r t i n g $ m a c h i n e : $port with g a t e w a y $ g a t e w a y .\ n ";
# print " cfg = $cfg \ n ";
# print " log = $log \ n ";
# open ( CFG_IN , " location - test - node . cfg . copy ")
open ( CFG_IN , $ c f g i n f i l e )
or die " Could not open $ c f g i n f i l e ";
open ( CFG_OUT , " > $cfg ") or die " Could not open $cfg ";
my % v a r i a b l e _ m a p = (" N o d e I D "
" GatewayID "
" GatewayCount "
" CacheDir "
" GatewayPort "
" DataManagerDebugLevel "
" ToPut "
" PutSize "
" IsUpdater "
" InitialData "
" WarmupTime "
" RunTime "
" ShowGUI "
" ADSH "
=>
=>
=>
=>
=>
=>
=>
=>
=>
=>
=>
=>
=>
=>
" $ h o s t n a m e : $port " ,
$gateway ,
$gateway_count ,
$blocksd i r ,
$port ,
$$data_manager_debug_level ,
$to_put ,
$put_size ,
$updater_var ,
$initial_data_var ,
$warmup_time ,
$run_time ,
$show_gui_var ,
$ a u t o m a t i c _ d a t a _ s u b m i s s i o n _ h a c k );
while ( < CFG_IN >) {
if ( m /\ $ \ { ( [ ^ } ] + ) \ } / ) {
my $ v a l u e = $ v a r i a b l e _ m a p { $1 };
if ( d e f i n e d $ v a l u e ) {
s /\ $ \ { ( [ ^ } ] + ) \ } / $ v a l u e /;
}
}
print C F G _ O U T $_ ;
}
close ( C F G _ I N );
close ( C F G _ O U T );
print " c o n f i g file : $cfg \ n ";
print " d i r n a m e : $ d i r n a m e \ n ";
# set up
‘ ln - sf
‘ ln - sf
‘ ln - sf
‘ ln - sf
‘ ln - sf
‘ ln - sf
‘ ln - sf
the links we need
../ s t o r e h e l p e r . pl $ d i r n a m e / s t o r e h e l p e r . pl ‘;
../ s u b m i t h e l p e r . pl $ d i r n a m e / s u b m i t h e l p e r . pl ‘;
../ r e c o n s t r u c t h e l p e r . pl $ d i r n a m e / r e c o n s t r u c t h e l p e r . pl ‘;
../ d i f f _ w i t h _ m a s t e r . pl $ d i r n a m e / d i f f _ w i t h _ m a s t e r . pl ‘;
../ a p p e n d _ n o t _ f o u n d . pl $ d i r n a m e / a p p e n d _ n o t _ f o u n d . pl ‘;
../ l o g _ r e t r i e v e _ r e q u e s t . pl $ d i r n a m e / l o g _ r e t r i e v e _ r e q u e s t . pl ‘;
../ a p p e n d f i l e d a t a . pl $ d i r n a m e / a p p e n d f i l e d a t a . pl ‘;
# now go to this node ’ s d i r e c t o r y
if (!( chdir (" $ d i r n a m e "))){
print (" f a i l e d to c h a n g e d i r e c t o r y .\ n ");
xlv
c l e a n u p ();
exit (1);
}
# clear the temp files from the e x p e r i m e n t s
# ‘ rm d i f f _ r e s u l t s . log ‘;
# - a is a p p e n d
exec ("../ m o d i f i e d _ r u n _ c f g . pl $ f i l e n a m e _ p r e f i x . cfg | tee $ f i l e n a m e _ p r e f i x . log ");
xlvi
Listing 9: modified run cfg.pl
#!/ usr / bin / perl
#
#
#
#
r u n _ c f g . pl
A n d r e w Logan
l o g a n a @ b c . edu , a n d r e w l o g a n @ g m a i l . com
10/25/04
# This file will run a b a m b o o . cfg file p a s s e d to it . W r i t t e n to save
# me some t y p i n g . Used for a u t o m a t i c t e s t i n g since I ’ m r u n n i n g it
# from a d i r e c t o r y in .
$ l e n g t h = $ # ARGV + 1;
if ( $ l e n g t h != 1){
print " P l e a s e enter a c o n f i g u r a t i o n file .\ n ";
exit (1);
}
$ c f g f i l e = @ARGV [0];
# this line a c t u a l l y s t a r t s the node
exec ( " . . / . . / bin / run - java b a m b o o . lss . D u s t D e v i l $ c f g f i l e ");
xlvii
Listing 10: base.cfg
# $Id : base . cfg , v 1.2 2 0 0 4 / 1 2 / 1 5 1 7 : 1 9 : 2 6 a n d r e w Exp $
# S a m p l e node c o n f i g u r a t i o n file .
< sandstorm >
< global >
< initargs >
node_id ${ NodeID }
</ initargs >
</ global >
< stages >
< Network >
class b a m b o o . n e t w o r k . N e t w o r k
< initargs >
udpcc_debug_level 0
</ initargs >
</ Network >
< Router >
class b a m b o o . r o u t e r . R o u t e r
< initargs >
debug_level
0
# If g a t e w a y _ c o u n t is -1 , only the value of g a t e w a y is
# used . Otherwise , the other g a t e w a y s are used . The
# r o u t e r code r e m o v e s our node from the g a t e w a y _ # list ,
# so we have to do it this way .
gateway_count
${ GatewayCount }
gateway_0
cslabgw1 :20000
gateway_1
cslabgw1 :20002
gateway_2
cslabgw1 :20004
gateway_3
cslabgw1 :20006
gateway_4
cslabgw1 :20008
gateway_5
cslabgw1 :20010
gateway_6
cslabgw1 :20012
gateway_7
cslabgw1 :20014
gateway_8
cslabgw1 :20016
gateway_9
cslabgw1 :20018
gateway_10
cslabgw1 :20020
gateway
${ GatewayID }
periodic_ping_period
20
ls_alarm_period
4
near_rt_alarm_period
0
far_rt_alarm_period
10
leaf_set_size
2
digit_values
2
ignore_proximity
false
location_cache_size
0
</ initargs >
</ Router >
< RouterCallbackInterface >
class b a m b o o . r o u t e r . R o u t e r C a l l b a c k I n t e r f a c e
< initargs >
</ initargs >
</ R o u t e r C a l l b a c k I n t e r f a c e >
< DataMan a g er >
class b a m b o o . dmgr . D a t a M a n a g e r
< initargs >
debug_level
0
merkle_tree_expansion 2
</ initargs >
</ DataMana g e r >
< StorageManager >
class b a m b o o . db . S t o r a g e M a n a g e r
< initargs >
debug_level
0
homedir
${ CacheDir }
</ initargs >
</ S t o r a g e M a n a g e r >
< DistCVSStage >
class t h e s i s . D i s t C V S S t a g e
< initargs >
xlviii
debug_level 0
logfile_name
d i f f _ r e s u l t s . log
automatic_test
true
updater_node
${ IsUpdater }
initial_data
${ InitialData }
show_gui
${ ShowGUI }
a u t o m a t i c _ d a t a _ s u b m i s s i o n _ h a c k $ { ADSH }
test_filename
foo1
test_projectname
foo1
#15 m i n u t e s
test_maxwait
900000
#12 m i n u t e s
test_minwait
720000
mean_put_period_ms
10000
mean_get_period_ms
10000
storage_goal
10240
test_warmup_time
${ WarmupTime }
test_run_time
${ RunTime }
client_stage_name GatewayClient
</ initargs >
</ D i s t C V S S t a g e >
< Dht >
class b a m b o o . dht . Dht
< initargs >
debug_level 0
storage_manager_stage StorageManager
</ initargs >
</ Dht >
< Gateway >
class b a m b o o . dht . G a t e w a y
< initargs >
debug_level 0
port $ { G a t e w a y P o r t }
</ initargs >
</ Gateway >
< GatewayClient >
class b a m b o o . dht . G a t e w a y C l i e n t
< initargs >
debug_level 0
gateway localhost :${ GatewayPort }
</ initargs >
</ G a t e w a y C l i e n t >
< PrintDataStage >
class t h e s i s . P r i n t D a t a S t a g e
</ P r i n t D a t a S t a g e >
< Vivaldi >
class b a m b o o . v i v a l d i . V i v a l d i
< initargs >
vc_type
2.5 d
generate_pings
true
eavesdrop_pings
false
u s e _ r e v e r s e _ p i n g true
ping_period
10000
version
1
</ initargs >
</ Vivaldi >
< WebInterface >
class b a m b o o . www . W e b I n t e r f a c e
< initargs >
storage_manager_stage StorageManager
</ initargs >
</ W e b I n t e r f a c e >
</ stages >
</ sandstorm >
xlix
Listing 11: make global experiment stats.pl
#!/ usr / bin / perl
#
# m a k e _ g l o b a l _ e x p e r i m e n t _ s t a t s . pl
# A n d r e w Logan
# l o g a n a @ b c . edu , a n d r e w l o g a n @ g m a i l . com
# 12/13/04
#
# This perl s c r i p t scans t h r o u g h the l o g f i l e s p r o d u c e d by e x p e r i m e n t
# runs and o u t p u t s some raw s t a t i s t i c s .
$ n u m _ r e q u e s t s = ‘ grep D A T A _ R E Q U E S T cslab *\:*/ d i f f _ r e s u l t s . log | wc -l ‘;
chomp ( $ n u m _ r e q u e s t s );
$ n u m _ g o o d _ v e r s i o n = ‘ grep G O O D _ V E R S I O N cslab *\:*/ d i f f _ r e s u l t s . log | wc -l ‘;
chomp ( $ n u m _ g o o d _ v e r s i o n );
$ n u m _ b a d _ v e r s i o n = ‘ grep B A D _ V E R S I O N cslab *\:*/ d i f f _ r e s u l t s . log | wc -l ‘;
chomp ( $ n u m _ b a d _ v e r s i o n );
$ n u m _ n o t _ f o u n d = ‘ grep N O T _ F O U N D cslab *\:*/ d i f f _ r e s u l t s . log | wc -l ‘;
chomp ( $ n u m _ n o t _ f o u n d );
$num_responses = $num_good_version + $num_bad_version + $num_not_found ;
$num_dangling = $num_requests - $num_responses ;
$percent_responded
$percent_good
$percent_bad
$percent_not_found
$percent_unanswered
=
=
=
=
=
$num_responses
$num_good_version
$num_bad_version
$num_not_found
$num_dangling
/
/
/
/
/
$num_requests ;
$num_responses ;
$num_responses ;
$num_responses ;
$num_requests ;
print " = = = = = R E S U L T S = = = = = \ n ";
print " n u m b e r of r e q u e s t s :
$ n u m _ r e q u e s t s \ n ";
print " n u m b e r of r e s p o n s e s :
$ n u m _ r e s p o n s e s \ n ";
print " n u m b e r of good v e r s i o n s :
$ n u m _ g o o d _ v e r s i o n \ n ";
print " n u m b e r of bad v e r s i o n s :
$ n u m _ b a d _ v e r s i o n \ n ";
print " n u m b e r of not f o u n d s :
$ n u m _ n o t _ f o u n d \ n ";
print " n u m b e r of u n a n s w e r e d r e q u e s t s : $ n u m _ d a n g l i n g \ n ";
print "==== P E R C E N T S = = = = = \ n ";
p r i n t f " p e r c e n t r e s p o n d e d : %.3 g \ n " , $ p e r c e n t _ r e s p o n d e d ;
p r i n t f " p e r c e n t good
: %.3 g \ n " , $ p e r c e n t _ g o o d ;
p r i n t f " p e r c e n t bad
: %.3 g \ n " , $ p e r c e n t _ b a d ;
p r i n t f " p e r c e n t not found : %.3 g \ n " , $ p e r c e n t _ n o t _ f o u n d ;
p r i n t f " p e r c e n t u n a n s w e r e d : %.3 g \ n " , $ p e r c e n t _ u n a n s w e r e d ;
l
Listing 12: process and send results.pl
#!/ usr / bin / perl
#
#
#
#
p r o c e s s _ a n d _ s e n d _ r e s u l t s . pl
A n d r e w Logan
l o g a n a @ b c . edu , a n d r e w l o g a n @ g m a i l . com
3/15/05
# W r i t t e n to a u t o m a g i c a l l y f o r m a t and e - mail the r e s u l t s of a long
# night ’ s a n a l y s i s .
$ h o s t n a m e = ‘ hostname ‘;
chomp ( $ h o s t n a m e );
if ( $ h o s t n a m e eq ’ cslabgw1 ’){
$ o u t p u t f i l e _ n a m e = " t o t a l _ r e s u l t s ";
$header_1
$header_2
$header_3
$header_4
$header_5
$header_6
$header_7
$header_8
=
=
=
=
=
=
=
=
"\ n100
"\ n200
"\ n300
"\ n100
"\ n200
"\ n300
"\ n100
"\ n300
nodes ,
nodes ,
nodes ,
nodes ,
nodes ,
nodes ,
nodes ,
nodes ,
m o d e r a t e rate :";
m o d e r a t e rate :";
m o d e r a t e rate :";
e x t r e m e rate :";
e x t r e m e rate :";
e x t r e m e rate :";
m o d e r a t e rate , u p d a t e s e n a b l e d :";
m o d e r a t e rate , u p d a t e s e n a b l e d :";
‘ echo " This is an a u t o m a t e d e - mail message , sent at the c o m p l e t i o n of the 8 e x p e r i m e n t runs .
-- A n d r e w " > $ o u t p u t f i l e _ n a m e ‘;
‘ echo \" $ h e a d e r _ 1 \" >> $ o u t p u t f i l e _ n a m e ‘;
‘ cat t e s t _ 1 _ r e s u l t s >> $ o u t p u t f i l e _ n a m e ‘;
‘ echo \" $ h e a d e r _ 2 \" >> $ o u t p u t f i l e _ n a m e ‘;
‘ cat t e s t _ 2 _ r e s u l t s >> $ o u t p u t f i l e _ n a m e ‘;
‘ echo \" $ h e a d e r _ 3 \" >> $ o u t p u t f i l e _ n a m e ‘;
‘ cat t e s t _ 3 _ r e s u l t s >> $ o u t p u t f i l e _ n a m e ‘;
‘ echo \" $ h e a d e r _ 4 \" >> $ o u t p u t f i l e _ n a m e ‘;
‘ cat t e s t _ 4 _ r e s u l t s >> $ o u t p u t f i l e _ n a m e ‘;
‘ echo \" $ h e a d e r _ 5 \" >> $ o u t p u t f i l e _ n a m e ‘;
‘ cat t e s t _ 5 _ r e s u l t s >> $ o u t p u t f i l e _ n a m e ‘;
‘ echo \" $ h e a d e r _ 6 \" >> $ o u t p u t f i l e _ n a m e ‘;
‘ cat t e s t _ 6 _ r e s u l t s >> $ o u t p u t f i l e _ n a m e ‘;
‘ echo \" $ h e a d e r _ 7 \" >> $ o u t p u t f i l e _ n a m e ‘;
‘ cat t e s t _ 7 _ r e s u l t s >> $ o u t p u t f i l e _ n a m e ‘;
‘ echo \" $ h e a d e r _ 8 \" >> $ o u t p u t f i l e _ n a m e ‘;
‘ cat t e s t _ 8 _ r e s u l t s >> $ o u t p u t f i l e _ n a m e ‘;
‘ mail - s \" A u t o m a t i c R e s u l t s R e p o r t !\" l o g a n a \ @bc . edu , s i g n o r i l \ @bc . edu , b o r o w s k y \ @bc . edu <
$ o u t p u t f i l e _ n a m e ‘;
}
else {
print " s k i p p i n g mail phase \ n ";
}
li
9
Appendix C: Bibliography
References
[1] B. Berliner.
CVS, The Concurrent Versioning System .
http://www.gnu.org/manual/cvs1.9/html chapter/cvs 2.html.
[2] I. Clarke, T. W. Hong, S. G. Miller, O. Sandberg, and
B. Wiley.
Protecting free expression online with freenet.
IEEE Internet Computing, 6(1):40--49, 2002.
[3] P. Druschel and A. Rowstron.
Past: A large-scale,
persistent peer-to-peer storage utility.
In HotOS VIII,
May 2001.
[4] S. P. Ratnasamy.
A Scalable Content-Addressable Network.
PhD thesis, Dept. Comp. Sci., University of California at
Berkeley, 2002.
[5] S. Rhea, D. Oppenheimer, S. Czerwinski, and B. Karp.
The
Bamboo Distributed Hash Table: A Robust, Open-Source DHT.
http://www.bamboo-dht.org, 2004.
[6] A. Rowstron and P. Druschel.
Pastry: Scalable,
decentralized object location, and routing for large-scale
peer-to-peer systems.
Lecture Notes in Computer Science,
2218:329--350, 2001.
[7] A. Sotira.
Step 1: What is Gnutella?
http://www.gnutella.com/news/4210, December 2001.
[8] I. Stoica, R. Morris, D. Karger, M. F. Kaashoek, and
H. Balakrishnan.
Chord: A scalable peer-to-peer lookup
service for internet applications.
In Proceedings of
the 2001 conference on applications, technologies,
architectures, and protocols for computer communications,
pages 149--160. ACM Press, 2001.
[9] U.S. Department of Commerce: Economics and Statistics
Administration: U.S. Census Bureau.
Home Computers
lii
and Internet Use in the United States: August 2000.
http://www.census.gov/prod/2001pubs/p23-207.pdf, 2001.
liii
Download