Adding documentation and a little bit of clean up
This commit is contained in:
parent
f935529b47
commit
d947a147c7
3
.gitignore
vendored
3
.gitignore
vendored
@ -8,6 +8,5 @@
|
|||||||
*.db
|
*.db
|
||||||
dfs_skel/
|
dfs_skel/
|
||||||
venv/
|
venv/
|
||||||
dn1/
|
dn*/
|
||||||
dn2/
|
|
||||||
copy_dir/
|
copy_dir/
|
||||||
|
17
Makefile
17
Makefile
@ -1,10 +1,19 @@
|
|||||||
all: build
|
all: build
|
||||||
|
|
||||||
dist: build
|
dist: clean build
|
||||||
@rm -f assig-03-dfs.tar.gz
|
@cp target/release/copy .
|
||||||
@cp target/release/copy copy
|
@cp target/release/ls .
|
||||||
@tar -czf assig-03-dfs.tar.gz src/ README.md copy
|
@cp target/release/data_node .
|
||||||
|
@cp target/release/meta_data .
|
||||||
|
@tar -czf assig-03-dfs.tar.gz src/ README.md copy ls data_node meta_data Cargo.* clean_db createdb.py
|
||||||
@rm copy
|
@rm copy
|
||||||
|
@rm ls
|
||||||
|
@rm data_node
|
||||||
|
@rm meta_data
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -f assig-03-dfs.tar.gz
|
||||||
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
cargo build --release
|
cargo build --release
|
||||||
|
83
README.md
83
README.md
@ -1,13 +1,85 @@
|
|||||||
## Distributed File System in Rust for CCOM4017
|
## Distributed File System in Rust for CCOM4017
|
||||||
|
|
||||||
#### Running
|
This suite of programs handles file copying over TCP with a client/server model.
|
||||||
|
It contains the following programs;
|
||||||
|
- copy
|
||||||
|
- ls
|
||||||
|
- data_node
|
||||||
|
- meta_data
|
||||||
|
|
||||||
```./copy <PARAM1> <PARAM2>```
|
`copy` and `ls` are clients that connect to the servers. `copy` sends file read and write requests
|
||||||
|
to the `meta_data` server, which uses a sqlite3 database to keep track of which nodes are connected,
|
||||||
|
as well as which files have been added. When a file is added, `meta_data` sends the list of available
|
||||||
|
`data_node` servers, `copy` then divides the file up by the amount of nodes, then proceeds to transfer
|
||||||
|
each chunk over 256 bytes at a time. `ls` simply prints out a list of the existing files on the
|
||||||
|
`meta_data` server.
|
||||||
|
|
||||||
#### Building
|
The code uses `serde_json` to serialize and deserialize Rust structs to and from json. The clients and
|
||||||
|
servers then listen for incoming streams of data and parses them as json. As well as exchanging
|
||||||
|
metadata, this protocol also establishes the handshake to then transfer the raw file chunks.
|
||||||
|
|
||||||
|
`rusqlite` is used for managing the sqlite database. This allows SQL queries to be performed from
|
||||||
|
the rust code and manage the data base in a relatively type safe way. Unit tests in the `meta_data`
|
||||||
|
provide coverage of these SQL operations against an in-memory version
|
||||||
|
|
||||||
|
### WARNING:
|
||||||
|
If you're my professor, please do not generate a database with the default `createdb.py`
|
||||||
|
provided in the skeleton dfs. I have included a custom version of the file in the root of the project.
|
||||||
|
The reason being that I changed chunks to be integers rather than strings, in order to provide ordering
|
||||||
|
to the chunks when transferring.
|
||||||
|
|
||||||
|
##### Running
|
||||||
|
|
||||||
|
To run the `ls` provide an endpoint in the _`ip:port`_ format. _`ip`_ can be _"localhost"_, consider
|
||||||
|
using `./` to avoid a naming conflict with the GNU version of `ls`
|
||||||
|
|
||||||
|
```$ ./ls 127.0.0.1:6770```
|
||||||
|
|
||||||
|
The `meta_data` server takes an optional port, but will default to `8000` if none is specified.
|
||||||
|
|
||||||
|
```$ meta_data 6710```
|
||||||
|
|
||||||
|
The data node takes two endpoints in the _`ip:port`_ and then a an optional path. The first endpoint
|
||||||
|
is the ip and port, both for binding to a TCP port and also to send itself to the `meta_data` server.
|
||||||
|
The second endpoint is the `meta_data` server's ip and port. The optional base path will default to the
|
||||||
|
working directory if none is provided.
|
||||||
|
|
||||||
|
```$ data_node localhost:6771 127.0.0.1:8000 my_cool_data_node```
|
||||||
|
|
||||||
|
The `copy` takes two different parameter versions, depending on whether it's sending to or receiving
|
||||||
|
from the server. To send a file, provide the path to the local file, then the endpoint with the file
|
||||||
|
in the _`ip:host:filepath`_ format. The `data_node` will save the file relative to the base path
|
||||||
|
provided to it.
|
||||||
|
|
||||||
|
```$ copy some_path/pug.jpg localhost:6700:another_path/pug.jpg```
|
||||||
|
|
||||||
|
To receive a file, simply invert the parameters
|
||||||
|
|
||||||
|
```$ copy localhost:6700:another_path/pug.jpg some_path/pug.jpg```
|
||||||
|
|
||||||
|
##### Misc Scripts
|
||||||
|
|
||||||
|
`shutdown_node` sends a json request with a provided port to shutdown a `data_node`. This ensures
|
||||||
|
that the node can terminate gracefully and unregister itself from the `meta_data` server. I was
|
||||||
|
advised against using Unix Signals, so opted for this instead.
|
||||||
|
|
||||||
|
```$ shutdown_node 6770```
|
||||||
|
|
||||||
|
`sm` just does a _send message_ to a provide port. It can be used to test and inspect jsons. It can
|
||||||
|
for instance be used to mimic the `ls`;
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sm '{"p_type":"ListFiles","json":null}' 8000
|
||||||
|
Connection to localhost 8000 port [tcp/*] succeeded!
|
||||||
|
{"paths":["pug.jpg 21633 bytes"]}%
|
||||||
|
```
|
||||||
|
|
||||||
|
`clean_db` just recreates the `dfs.db` with the custom python script.
|
||||||
|
|
||||||
|
##### Building
|
||||||
|
|
||||||
If you wish to compile the code, install rust and cargo
|
If you wish to compile the code, install rust and cargo
|
||||||
[Link](https://www.rust-lang.org/en-US/install.html)
|
[link](https://www.rust-lang.org/en-US/install.html)
|
||||||
|
|
||||||
Then just run build
|
Then just run build
|
||||||
|
|
||||||
@ -17,5 +89,6 @@ If you wish to run a specific algorithm;
|
|||||||
|
|
||||||
```cargo run --bin copy ```
|
```cargo run --bin copy ```
|
||||||
|
|
||||||
#### Testing
|
##### Testing
|
||||||
|
|
||||||
|
`cargo test --bin meta_data`
|
||||||
|
@ -1,25 +1,23 @@
|
|||||||
extern crate a03;
|
extern crate a03;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
#[macro_use]
|
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
use a03::*;
|
use a03::*;
|
||||||
use std::net::{TcpStream, Shutdown};
|
use std::net::{TcpStream, Shutdown};
|
||||||
use std::io::{Write, Read};
|
use std::io::{Write, BufWriter};
|
||||||
use std::net::TcpListener;
|
use std::net::TcpListener;
|
||||||
use serde_json::from_str;
|
use serde_json::from_str;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io::BufWriter;
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let node_endpoint = parse_endpoint_from_cli(0);
|
let node_endpoint = parse_endpoint_from_cli(0);
|
||||||
let metadata_endpoint = parse_endpoint_from_cli(1);
|
let metadata_endpoint = parse_endpoint_from_cli(1);
|
||||||
let data_path = std::env::args().skip(3).next()
|
let data_path = std::env::args().skip(3).next()
|
||||||
.expect("Missing data path");
|
.unwrap_or(String::from("."));
|
||||||
let listener = TcpListener::bind(&node_endpoint).unwrap();
|
let listener = TcpListener::bind(&node_endpoint).unwrap();
|
||||||
register_with_meta_server(&metadata_endpoint, &node_endpoint);
|
register_with_meta_server(&metadata_endpoint, &node_endpoint);
|
||||||
|
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
extern crate a03;
|
extern crate a03;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
#[macro_use]
|
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
use a03::*;
|
use a03::*;
|
||||||
use std::net::{TcpListener, TcpStream, Shutdown, SocketAddrV4, Ipv4Addr};
|
use std::net::{TcpStream, Shutdown };
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::thread;
|
|
||||||
use std::io::Read;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -91,7 +91,7 @@ pub struct BlockQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_endpoint_from_cli(arg_index : usize) -> String {
|
pub fn parse_endpoint_from_cli(arg_index : usize) -> String {
|
||||||
let mut args: Vec<String> = std::env::args().skip(1).collect();
|
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||||
let endpoint_arg: String = args.get(arg_index).expect("No IP provided").clone();
|
let endpoint_arg: String = args.get(arg_index).expect("No IP provided").clone();
|
||||||
|
|
||||||
if endpoint_arg.contains(":") {
|
if endpoint_arg.contains(":") {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user