Skip to content

Final project for the Operating Systems course @ UniPi 20-21

License

Notifications You must be signed in to change notification settings

lucadp19/SOL-Project-2021

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SOL-Project-2021

A file-storage server

This repo contains my version of the final project for the Lab module of the Operating Systems and Lab course at UniPi, Academic Year 2020-2021. The project is released under a MIT License.

It implements a simple file-storage server that receives files and concurrent requests from several clients. The server process stores the files in memory (RAM) and acts as a file cache: whenever the reserved space is full files are ejected and sent back to clients. The client-server communication is based on an API library that implements the protocol for several operations, such as opening/reading/writing files and many more.

General structure

The main source files are in the src/ subdirectory; include files are in includes/. The obj/ and libs/ subdirectory are used for object files and dynamic libraries generated at compile time. The bin/ subdirectory will contain the executables after a successfull compilation.

config/ contains a single file, config/config.txt which specifies the main parameters for the server process.

logs/ is the default directory in which log files written by the server app are stored. They can be parsed and analysed through the scripts/statistiche.sh script (which will be described later).

report/ contains a report on the main implementation details of this project (written in italian).

scripts/ contains some Bash scripts used to implement tests.

tests/ contains random files to test some aspect of the project (mainly the client options and the replacement algorithm).

Some directories contain a .keep file: this file is used only to ensure that Git loads the directory.

Compilation

A Makefile was created to ease the compilation procedure. It supports several options:

  • make compiles the whole project, creating the directories for object files, binaries and libraries if they don't exist
  • make clean cleans all auxiliary files and executables
  • make test1 and make test2 launch respectively the first and the second test. In particular the second test provides two more options:
    • make test2FIFO to test the FIFO replacement algorithm
    • make test2LRU to test the Least Recently Used replacement algorithm In the current version, make test2 is equivalent to make test2LRU.
  • make cleanTest1, make cleanTest2 and make cleanTests to clean files generated by the various tests
  • make stats tries to analyse the last log file present in logs/ using the scripts/statistiche.sh script.

Server config file

The server config file is (by default) located in config/config.txt but can optionally be specified by passing the config path as an additional argument to the server executable. The config.txt file has the following format:

    no_worker = <number of worker threads>
    max_space = <max space in MBytes>
    max_files = <max number of files>
    cache_pol = <cache replacement policy, may be FIFO or LRU>
    sock_path = <path to socket file>
    path_dlog = <path to the directory containing log files>

There might be any number of spaces before or after the equal sign, or any number of empty lines between two different key=value lines, but all keywords must be present once and only once.

Client options

A possible client is implemented and (after a successfull compilation) may be executed by giving the command ./bin/client. All options and requests are given to the client through the command line. The possible optional argument can be seen with the option -h.

API

The communication client-server is implemented through a dynamically linked library libapi.so. The API library may be freely used with a different client, but since it depends on a utility library libutil.so the two must be linked to the client object files.

Scripts

The scripts directory contains some useful scripts:

  • scripts/create_dirs.sh creates several subdirectories (such as obj/, bin/, libs/, logs/ and others) if they don't already exist (it is automatically called by make);
  • scripts/test1.sh and scripts/test2.sh are two tests (they may also be called through the Makefile, as described before). In particular the latter might be called with an optional argument representing the chosen replacement algorithm, which must be either FIFO or LRU. If no optional argument is given, LRU is assumed;
  • scripts/statistiche.sh computes some statistics on a log file generated by the server: if an optional argument is given it's interpreted as the path to a log file, otherwise the scripts takes the last log file present in the logs/ directory.

Optional features

The following table describes what optional features (optional for the summer exam term) were implemented.

Feature Implemented?
LRU alg.
LFU alg.
Log files
File stats.sh
Compression
test3
Send files to client (option -D)
Lock (-l)
Unlock (-u)

Possible improvements and errors

  • Source files don't have to be so split up. It isn't an error and I did it for my own sanity, but it isn't necessary.
  • To improve the logging performance, the logger function might maintain an internal buffer - that is, a list of things to print - and print the whole buffer once it reaches a certain capacity.
  • The logger should print something in case of fatal errors - for example a failed safe_malloc, that automatically aborts the process with an exit(EXIT_FAILURE).
  • Utility functions (such as those in the libutil.so library, like safe_malloc or safe_pthread_*) mustn't abort the process without giving any choice to the programmer, even if the error is always fatal.
    • One way to solve this problem is to add an additional bool parameter to those functions: if the parameter is true on error the process is aborted, otherwise an error code is returned. This way the programmer may use the function safely and with full control over the function's behaviour.