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