The Google File System : part1 ABSTRACT and INTRODUCTION

本文介绍了一种用于大型分布式数据密集型应用的可扩展分布式文件系统——Google文件系统(GFS)。GFS在运行于廉价商品硬件上时提供容错能力,并为大量客户端提供高性能。文章详细介绍了GFS的设计考量,包括组件故障的处理、大文件的支持、数据的追加方式以及应用程序和文件系统API的协同设计。
ABSTRACT
We have designed and implemented the Google File System, a scalable distributed file system for large distributed data-intensive applications. 
It provides fault tolerance while running on inexpensive commodity hardware, and it delivers high aggregate performance to a large number of clients.

摘要
我们已经设计并实施了Google File System,这是一种用于大型分布式数据密集型应用的可扩展分布式文件系统。
它在运行在廉价商品硬件上时提供容错,并为大量客户端提供高集总性能。

While sharing many of the same goals as previous distributed file systems, our design has been driven by observations of our application workloads and technological environment, both current and anticipated, that reflect a marked departure from some earlier file system assumptions. 
This has led us to reexamine traditional choices and explore radically different design points.
The file system has successfully met our storage needs.
It is widely deployed within Google as the storage platform for the generation and processing of data used by our service as well as research and development efforts that require large data sets. 
The largest cluster to date provides hundreds of terabytes of storage across thousands of disks on over a thousand machines, and it is concurrently accessed by hundreds of clients.
In this paper, we present file system interface extensions designed to support distributed applications, discuss many aspects of our design, and report measurements from both micro-benchmarks and real world use.

在与以前的分布式文件系统共享许多相同的目标的同时,我们的设计是由我们的应用程序工作负载和当前和预期的技术环境的观察驱动的,这反映了一些较早的文件系统假设的明显偏离。
这导致我们重新审视传统选择,探索完全不同的设计点。
文件系统已经成功地满足了我们的存储需求。
它在Google中广泛部署为用于生成和处理我们服务使用的数据的存储平台以及需要大数据集的研究和开发工作。
迄今为止,最大的集群在千台机器上的数千个磁盘上提供了数百TB的存储空间,并由数百个客户端同时访问。
在本文中,我们提出了旨在支持分布式应用程序的文件系统接口扩展,讨论了我们设计的许多方面,并从微型基准和现实世界中使用报告测量。

Categories and Subject Descriptors

Distributed file systems

General Terms
Design, reliability, performance, measurement
Keywords : Fault tolerance, scalability, data storage, clustered storage
The authors can be reached at the following addresses:
{sanjay,hgobioff,shuntak}@google.com.

类别和主题描述符
分布式文件系统
一般条款
设计,可靠性,性能,测量
关键词 : 容错,可扩展性,数据存储,集群存储
作者可以在以下地址达到:
{桑杰,hgobioff,shuntak}@ google.com。

1. INTRODUCTION
We have designed and implemented the Google File System (GFS) to meet the rapidly growing demands of Google’s data processing needs. 
GFS shares many of the same goals as previous distributed file systems such as performance, scalability, reliability, and availability. 
However, its design has been driven by key observations of our application workloads and technological environment, both current and anticipated, that reflect a marked departure from some earlier file system design assumptions.
We have reexamined traditional choices and explored radically different points in the design space.

1.介绍
我们设计和实施了Google文件系统(GFS),以满足Google数据处理需求日益增长的需求。
GFS与以前的分布式文件系统具有许多相同的目标,例如
性能,
可扩展性,
可靠性和
可用性。
然而,其设计是由我们的应用工作负载和当前和预期的技术环境的重要观察所驱动的,反映出与早期文件系统设计假设的明显偏差。
我们重新审视了传统选择,并在设计领域探索了根本性的不同点。

First, component failures are the norm rather than the exception. 
The file system consists of hundreds or even thousands of storage machines built from inexpensive commodity parts and is accessed by a comparable number of client machines. 
The quantity and quality of the components virtually guarantee that some are not functional at any given time and some will not recover from their current failures. 
We have seen problems caused by application bugs, operating system bugs, human errors, and the failures of disks, memory, connectors,networking, and power supplies. 
Therefore, constant monitoring, error detection, fault tolerance, and automatic recovery must be integral to the system.

(1)组件故障是规范而不是异常。
文件系统由数百甚至数千个由廉价商品部件构成的存储机器组成,可由相当数量的客户端机器访问。
组件的数量和质量实际上保证了某些在任何给定的时间都不起作用,有些不能从当前的故障中恢复。
我们已经看到由应用程序错误,操作系统错误,人为错误以及磁盘,内存,连接器,网络和电源的故障引起的问题。
因此,不断的监控,错误检测,容错和自动恢复必须是系统的一部分。

Second, files are huge by traditional standards. Multi-GB files are common. 
Each file typically contains many application objects such as web documents. 
When we are regularly working with fast growing data sets of many TBs comprising billions of objects, it is unwieldy to manage billions of approximately KB-sized files even when the file system could support it. 
As a result, design assumptions and parameters such as I/O operation and block sizes have to be revisited.

(2)传统标准文件是巨大的。 多GB文件是常见的。
每个文件通常包含许多应用程序对象,如Web文档。
当我们经常使用包含数十亿个对象的许多TB的快速增长数据集时,即使文件系统可以支持它,也难以管理数十亿个大小的KB大小的文件。
因此,必须重新设计I/O操作和块大小等设计假设和参数。

Third, most files are mutated by appending new data rather than overwriting existing data. 
Random writes within a file are practically non-existent. 
Once written, the files are only read, and often only sequentially. 
A variety of data share these characteristics. 
Some may constitute large repositories that data analysis programs scan through. 
Some may be data streams continuously generated by running applications. 
Some may be archival data. 
Some may be intermediate results produced on one machine and processed on another, whether simultaneously or later in time. 
Given this access pattern on huge files, appending becomes the focus of performance optimization and atomicity guarantees,while caching data blocks in the client loses its appeal.

(3)大多数文件通过附加新数据而不是覆盖现有数据进行突变。
文件中的随机写入实际上不存在。
一旦写入,文件只能读取,而且通常只能顺序执行。
各种数据共享这些特点。
有些可能构成数据分析程序扫描的大型存储库。
一些可能是运行应用程序连续生成的数据流。
有些可能是存档数据。
一些可能是在一台机器上产生的中间结果,并在另一台机器上进行处理,无论是在时间上还是之后。
鉴于这种大型文件的访问模式,追加成为性能优化和原子性保证的重点,而客户端缓存数据块则失去了吸引力。

Fourth, co-designing the applications and the file system API benefits the overall system by increasing our flexibility.
For example, we have relaxed GFS’s consistency model to vastly simplify the file system without imposing an onerous burden on the applications. 
We have also introduced an atomic append operation so that multiple clients can append concurrently to a file without extra synchronization between them. 
These will be discussed in more details later in the paper.

(4)通过增加我们的灵活性,共同设计应用程序和文件系统API将有利于整个系统。
例如,我们放宽了GFS的一致性模型,大大简化了文件系统,而不会对应用程序造成沉重的负担。
我们还引入了一个原子附加操作,以便多个客户端可以并发地附加到一个文件,而不需要额外的同步。
这些将在本文后面的更详细的讨论。

Multiple GFS clusters are currently deployed for different purposes. 
The largest ones have over 1000 storage nodes, over 300 TB of disk storage, and are heavily accessed by hundreds of clients on distinct machines on a continuous basis.

目前为了不同的目的部署了多个GFS集群。
最大的存储节点有超过1000个存储节点,超过300 TB的磁盘存储,并且在不同的机器上被数百个客户端连续访问。
Your library system is steadily evolving. Users can now log in, borrow, and return books with ease. But one problem remains: finding the right book isn't always so easy. The current search function only works if users know the exact title. Imagine being a stressed student during exam week, remembering only "something about machine learning" but not the full book title -- frustrating, right? The librarians want to fix this by introducing a keyword-based search, so users can explore the catalogue more naturally. On top of that, the university has just secured extra funding to expand the collection, and your system must now support adding brand-new books into the database. Task Description Updated Main Menu For students, staff (non-library) and other users, a new option, Search by Keywords (Option 5), is added to the main menu. Logged in as Chris Manner (Student) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: For library staff, alongside Search by Keywords (option 5), the existing Library Report option is expanded into Manage Library (option 6), offering more administrative features (described later). Logged in as Mary Alan (Staff) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords 6. Manage Library ================================== Enter your choice: Renew loan All users may renew each borrowed book once, using the command renew <book ID> in the Borrow and Return console. Renewal extends the due date by 5 days. If the user has borrowed multiple copies of the same book, the system will renew the copy (or loan) with the earliest due date first. A book is not eligible for renewal if: Its extended due date has already passed (making it overdue). An error message "Renewal denied: This book is already overdue." will be printed out instead. If it is already renewed once by the user, the system will display "Renewal unavailable: Each book can only be renewed once." Users with unpaid fines cannot renew any loans until their fines are settled. The system will display "Renewal denied: You have unpaid fines." Returning validation priority is similar to borrowing validation priority in Task 2. The system first checks whether the user is eligible to renew. Then it verifies if the loan is valid and is eligible to renew. Logged in as Chris Manner (Student) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: 4 > renew P0011 Renewal denied: You have unpaid fines. An error will return if the loan record does not exist Logged in as Noah (Others) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: 4 > renew P0011 No loan record for P0011. Search by Keywords Upon entering 5, the system will prompt them to enter a list of keywords (case insensitive), separated by commas (,). The program will then search the catalogue and return a list of books that contain at least one of the specified keywords. The results will be sorted in the following order of priority: Number of matched keywords (highest first) Publication year (newest first) Book ID (ascending order) If the keyword list is empty, the program should return "Found 0 book(s)." Logged in as Noah (Others) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: 5 Enter search keywords (separated by comma): python,programming Found 7 book(s). 1. P0003 'Python Crash Course' by Eric Matthes (2023). 2. P0001 'Introduction to Python Programming' by S Gowrishankar (2019). 3. E0002 'Deep learning with Python: a hands-on introduction' by Ketkar Nikhil (2017). 4. E0001 'Python Crash Course' by Eric Matthes (2015). 5. P0002 'Python Programming: An Introduction to Computer Science' by John M. Zelle (2002). 6. E0003 'Machine Learning for Business' by Doug Hudgeon & Richard Nichol (2020). 7. P0006 'Hands-On ML' by Aurelien Geron (2019). Manage Library (Library Staff only) When staff members select option 6 to enter the Manage Library console, they can perform the following actions: Print library report by enter report Add a New Book Use the command add physical to add a new physical book, or add online to add a new online book. The system will then prompt the user to provide the book’s details, including title, authors, year, number of copies (required for physical books only) The system will automatically assign keywords to newly added books by matching any words in their titles with the existing keyword list from the books.csv dataset (sorted by alphabet order). Each new book is assigned a unique ID: IDs for physical books begin with P. IDs for online books begin with E. The numeric portion of the ID is generated by incrementing the highest existing ID of that type in the library. Type quit to exit the borrow and return console and go back to main menu. Logged in as Mary Alan (Staff) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords 6. Manage Library ================================== Enter your choice: 6 > report Library Report - 9 users, including 4 student(s), 3 staff and 2 others. - 14 books, including 10 physical book(s) (7 currently available) and 3 online book(s). > add physical Title: A Concise and Practical Introduction to Programming Algorithms in Java Authors: Nielsen Frank Year: 2017 Copies: 1 Detected keywords: algorithms:programming Adding P0020 'A Concise and Practical Introduction to Programming Algorithms in Java' by Nielsen Frank (2017). Examples Example 1 Welcome to Library Login as: s31267 Password: chr1267 Logged in as Chris Manner (Student) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: 2 Student Chris Manner. Policies: maximum of 10 days, 4 items. Current loans: 2 (1 physical / 1 online). Fines: $ 1.00 ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: 3 You are currently have 2 loan(s). 1. P0006 'Hands-On ML' by Aurelien Geron (2019). Due date: 13/09/2025. 2. E0001 'Python Crash Course' by Eric Matthes (2015). Due date: 15/09/2025. ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: 4 > renew P0101 Renewal denied: You have unpaid fines. > return P0006 Returned 'Hands-On ML' by Aurelien Geron (2019). Overdue by 2 day(s). Fine: $ 1.00 > renew E0001 Renewal denied: This book is already overdue. > return E0001 Returned 'Python Crash Course' by Eric Matthes (2015). > borrow The Hobbit Found 1 book(s). - P0008 (physical) 'The Hobbit' by J.R.R. Tolkien (1937). Available copies: 1/2. Confirm the Book ID you'd like to borrow: P0008 You have borrowed 'The Hobbit' by J.R.R. Tolkien (1937). Due: 25/09/2025. > renew P0008 Renew 'The Hobbit' by J.R.R. Tolkien (1937) successfully. New due date: 30/09/2025 > quit ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: 3 You are currently have 1 loan(s). 1. P0008 'The Hobbit' by J.R.R. Tolkien (1937). Due date: 30/09/2025. ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: 0 Goodbye! Example 2 Welcome to Library Login as: o56799 Password: noa6799 Logged in as Noah (Others) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: 5 Enter search keywords (separated by comma): python,programming Found 7 book(s). 1. P0003 'Python Crash Course' by Eric Matthes (2023). 2. P0001 'Introduction to Python Programming' by S Gowrishankar (2019). 3. E0002 'Deep learning with Python: a hands-on introduction' by Ketkar Nikhil (2017). 4. E0001 'Python Crash Course' by Eric Matthes (2015). 5. P0002 'Python Programming: An Introduction to Computer Science' by John M. Zelle (2002). 6. E0003 'Machine Learning for Business' by Doug Hudgeon & Richard Nichol (2020). 7. P0006 'Hands-On ML' by Aurelien Geron (2019). ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: 4 > borrow E0003 Found 1 book(s). - E0003 (online) 'Machine Learning for Business' by Doug Hudgeon & Richard Nichol (2020). Available copies: 0/0. Confirm the Book ID you'd like to borrow: E0003 You have borrowed 'Machine Learning for Business' by Doug Hudgeon & Richard Nichol (2020). Due: 22/09/2025. > quit ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: 3 You are currently have 1 loan(s). 1. E0003 'Machine Learning for Business' by Doug Hudgeon & Richard Nichol (2020). Due date: 22/09/2025. ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords ================================== Enter your choice: 0 Goodbye! Example 3 Welcome to Library Login as: e118102 Password: pa55word Logged in as Mary Alan (Staff) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords 6. Manage Library ================================== Enter your choice: 6 > report Library report - 9 users, including 4 student(s), 3 staff, and 2 others. - 14 books, including 10 physical book(s) (7 currently available) and 4 online book(s). > add physical Title: A Concise and Practical Introduction to Programming Algorithms in Java Authors: Nielsen Frank Year: 2017 Copies: 1 Detected keywords: algorithms:programming Adding P0020 'A Concise and Practical Introduction to Programming Algorithms in Java' by Nielsen Frank (2017). > report Library report - 9 users, including 4 student(s), 3 staff, and 2 others. - 15 books, including 11 physical book(s) (8 currently available) and 4 online book(s). > quit ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Borrow and Return 5. Search by Keywords 6. Manage Library ================================== Enter your choice: 0 Goodbye!import user import book import csv import datetime from datetime import timedelta import typing def parse_date(date_str: str) -> typing.Optional[datetime.date]: if not date_str or date_str.strip() == "None": return None day, month, year = map(int, date_str.split('/')) return datetime.date(year, month, day) def load_users(file_path: str) -> dict: users = {} with open(file_path, newline='') as csvfile: reader = csv.reader(csvfile) next(reader) for row in reader: user_id, password, name, role, department = row role = row[3].capitalize() if user_id.startswith('s'): u = user.Student(user_id, password, name, role, None) elif user_id.startswith('e'): u = user.Staff(user_id, password, name, role, department) else: role = "Others" u = user.Other(user_id, password, name, role, None) users[user_id] = u return users def load_books(file_path: str) -> dict: books = {} with open(file_path, newline='') as csvfile: reader = csv.reader(csvfile) next(reader) for row in reader: book_id, book_type, copies, title, author, year, keywords = row b = book.Book(book_id, book_type, int(copies), title, author, int(year), keywords) books[book_id] = b b.loans = [] return books def load_loans(file_path: str, users: dict, books: dict): loans = [] with open(file_path, newline='') as csvfile: reader = csv.reader(csvfile) next(reader) for row in reader: user_id, book_id, borrow_date, due_date, return_date = row if user_id in users and book_id in books: loan = Loan(users[user_id], books[book_id], borrow_date, due_date, return_date) users[user_id].add_loan(loan) books[book_id].loans.append(loan) loans.append(loan) return loans def borrow_return_console(user, books, users): TODAY = datetime.datetime.strptime("15/09/2025", "%d/%m/%Y").date() while True: cmd = input("> ").strip() if cmd == "quit": return part = cmd.split(' ', 1) if len(part) < 2: continue action, query = part[0].lower(), part[1] if action == "borrow": matched_books = [] for b in books.values(): if query.lower() in b.title.lower() or query == b.book_id: matched_books.append(b) matched_books.sort(key=lambda x: x.book_id) if not matched_books: print(f"No books match '{query}'.") continue physical_match = [b for b in matched_books if b.book_type == "physical"] online_match = [b for b in matched_books if b.book_type == "online"] available_str = sum(b.available_copies() for b in physical_match) print(f"Found {len(matched_books)} book(s).") all_matches = physical_match + online_match all_matches.sort(key=lambda x: x.book_id) for b in all_matches: copies = f"Available copies: {available_str}/{b.total_copies}" if b.book_type == "physical" else "Available copies: 0/0" print(f"- {b.book_id} ({b.book_type}) '{b.title}' by {b.authors} ({b.year}). {copies}.") valid_ids = [b.book_id for b in all_matches] while True: borrowid = input(f"Confirm the Book ID you'd like to borrow: ").strip() if borrowid == "quit": break if borrowid not in valid_ids: continue book = books[borrowid] unpaid_fine = sum(loan.calculate_fine() for loan in user.get_active_loans()) if unpaid_fine > 0: print("Borrowing unavailable: unpaid fines. Review your loan details for more info.") break current_physical = sum(1 for loan in user.get_active_loans() if loan.book.book_type == "physical") if current_physical >= user.get_loan_policy()["quota"]: print("Borrowing unavailable: quota reached. Review your loan details for more info.") break if book.book_type == "physical" and book.available_copies() <= 0: print("No copies available.") break due_days = user.get_loan_policy()["days"] due_date = TODAY + timedelta(days = due_days) borrow_str = TODAY.strftime("%d/%m/%Y") due_str = due_date.strftime("%d/%m/%Y") return_str = "None" loan = Loan(user, book, borrow_str, due_str, return_str) user.loans.append(loan) book.loans.append(loan) print(f"You have borrowed '{book.title}' by {book.authors} ({book.year}). Due: {due_date.strftime('%d/%m/%Y')}.") break elif action == "return": borrowid = query.strip() if borrowid not in books: print("No loan record for {}.".format(borrowid)) continue book = books[borrowid] active_loans = [loan for loan in user.get_active_loans() if loan.book.book_id == borrowid] if not active_loans: print(f"No loan record for {borrowid}.") continue loan_to_return = min(active_loans, key=lambda x: x.due_date) user.loans.remove(loan_to_return) return_date = TODAY fine_amount = 0.0 overdue_days = 0 if book.book_type == "physical" and return_date > loan_to_return.due_date: grace = {"Student": 0, "Staff": 2, "Others": 0}[user.role] effective_due = loan_to_return.due_date + timedelta(days = grace) overdue_days = max(0, (TODAY - effective_due).days) rate = 0.50 if user.role in ['Student', 'Staff'] else 1.00 fine_amount = overdue_days * rate status = f"Returned '{book.title}' by {book.authors} ({book.year})." if overdue_days > 0: status += f" Overdue by {overdue_days} day(s). Fine: $ {fine_amount:.2f}" print(status) else: continue class Loan: def __init__(self, user, book, borrow_str, due_str, return_str): self.user = user self.book = book self.borrow_date = parse_date(borrow_str) self.due_date = parse_date(due_str) self.return_date = parse_date(return_str) def calculate_fine(self): TODAY = datetime.datetime.strptime("15/09/2025", "%d/%m/%Y").date() if self.book.book_type == "online": return 0.0 if TODAY <= self.due_date: return 0.0 grace = {"Student": 0, "Staff": 2, "Others": 0}[self.user.role] effective_due = self.due_date + timedelta(days = grace) overdue_days = max(0, (TODAY - effective_due).days) rate = 0.50 if self.user.role in ['Student', 'Staff'] else 1.00 return overdue_days * rate def main(user_file: str, book_file:str, loan_file:str) -> None: """ This is the entry of your program. Please DO NOT modify this function signature, i.e. function name, parameters Parameteres: - user_file (str): path the `users.csv` which stores user information - book_file (str): path the `books.csv` which stores book information - loan_file (str): path the `loans.csv` which stores loan information """ # Your implemetation goes here users = load_users(user_file) books = load_books(book_file) load_loans(loan_file, users, books) while True: print("Welcome to Library") user_input = input("Login as: ").strip() if user_input == "quit": print("Goodbye!") return else: password = input("Password: ").strip() if user_input not in users or users[user_input].password != password: print("Invalid credentials. 2 attempt(s) remaining.") user_input = input("Login as: ").strip() password = input("Password: ").strip() if user_input not in users or users[user_input].password != password: print("Invalid credentials. 1 attempt(s) remaining.") user_input = input("Login as: ").strip() password = input("Password: ").strip() if user_input not in users or users[user_input].password != password: print("Sorry you're out of attempts. Please contact your librarian for assistance.") continue current_user = users[user_input] print(f"Logged in as {current_user.name} ({current_user.role})") while True: menu = [ "My Library Account", "0. Quit", "1. Log out", "2. View account policies", "3. View my loans", "4. Borrow and Return" ] if current_user.is_library_staff(): menu.append("5. Library Report") print("=" * 34) for item in menu: print(item) print("=" * 34) while True: try: choice = input("Enter your choice: ").strip() if not choice.isdigit() or choice not in ['0', '1', '2', '3', '4', '5']: continue choice = int(choice) break except: continue if choice == 0: print("Goodbye!") return elif choice == 1: break elif choice == 2: policy = current_user.get_loan_policy() active_loans = current_user.get_active_loans() num_loans = len(active_loans) phys, online = current_user.get_physical_online_count() total_fine = sum(loan.calculate_fine() for loan in active_loans) print(f"{current_user.role} {current_user.name}. Policies: maximum of {policy['days']} days, {policy['quota']} items. Current loans: {num_loans} ({phys} physical / {online} online). Fines: $ {total_fine:.2f}") elif choice == 3: active_loans = sorted(current_user.get_active_loans(), key=lambda x: x.due_date) count = len(active_loans) print(f"You are currently have {count} loan(s).") for i, loan in enumerate(active_loans, 1): print(f"{i}. {loan.book.book_id} '{loan.book.title}' by {loan.book.authors} ({loan.book.year}). Due date: {loan.due_date.strftime('%d/%m/%Y')}.") elif choice == 4: borrow_return_console(current_user, books, users) elif choice == 5: total_user = len(users) students = sum(1 for u in users.values() if u.user_id.startswith('s')) staffs = sum(1 for u in users.values() if u.user_id.startswith('e')) others = sum(1 for u in users.values() if u.user_id.startswith('o')) total_books = len(books) physical_books = sum(1 for b in books.values() if b.book_type == "physical") available_physical = sum(1 for b in books.values() if b.book_type == "physical" and b.is_available()) online_books = sum(1 for b in books.values() if b.book_type == "online") print("Library report") print(f"- {total_user} users, including {students} student(s), {staffs} staff, and {others} others.") print(f"- {total_books} books, including {physical_books} physical book(s) ({available_physical} currently available) and {online_books} online book(s).") else: continue if __name__ == "__main__": main('data/users.csv', 'data/books.csv', 'data/loans.csv') import csv import datetime import re class Book: # your code goes here def __init__(self, book_id: str, book_type: str, total_copies: int, title: str, authors: str, year: int, keywords: str): self.book_id = book_id self.book_type = book_type self.total_copies = total_copies self.title = title self.authors = authors self.year = year self.keywords = keywords.split(':') if keywords else [] self.loans = [] def available_copies(self): borrowed_count = sum(1 for loan in self.loans if loan.return_date is None) return self.total_copies - borrowed_count def is_available(self) -> bool: if self.book_type == "online": return True borrowed_count = sum(1 for loan in self.loans if loan.return_date is None) return borrowed_count < self.total_copies def __str__(self): return f"{self.title} by {self.authors} ({self.year})"from abc import ABC, abstractmethod import csv import datetime import re TODAY = "15/09/2025" class User(ABC): # Your code goes here def __init__(self, user_id: str, password: str, name: str, role: str, department: str = None): self.user_id = user_id self.password = password self.name = name self.role = role self.department = department self.loans = [] @abstractmethod def get_loan_policy(self): pass def is_library_staff(self) -> bool: return self.role == "Staff" and self.department == "Library" def add_loan(self, loan): self.loans.append(loan) def get_active_loans(self): return [loan for loan in self.loans if loan.return_date is None] def get_physical_online_count(self): physical = sum(1 for loan in self.get_active_loans() if loan.book.book_type == "physical") online = sum(1 for loan in self.get_active_loans() if loan.book.book_type == "online") return physical, online def __str__(self): return f"{self.name} ({self.role})" class Student(User): def get_loan_policy(self): return {"days": 10, "quota": 4} class Staff(User): def get_loan_policy(self): return {"days": 14, "quota": 6} class Other(User): def get_loan_policy(self): return {"days": 7, "quota": 2}
最新发布
10-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值