2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* file_access_network.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "file_access_network.h"
2018-09-11 18:13:45 +02:00
2020-11-07 23:33:38 +01:00
# include "core/config/project_settings.h"
2018-09-11 18:13:45 +02:00
# include "core/io/ip.h"
# include "core/io/marshalls.h"
# include "core/os/os.h"
2014-02-10 02:10:30 +01:00
2016-01-20 04:29:34 +01:00
//#define DEBUG_PRINT(m_p) print_line(m_p)
2014-02-10 02:10:30 +01:00
//#define DEBUG_TIME(m_what) printf("MS: %s - %lli\n",m_what,OS::get_singleton()->get_ticks_usec());
2016-01-20 04:29:34 +01:00
# define DEBUG_PRINT(m_p)
2014-02-10 02:10:30 +01:00
# define DEBUG_TIME(m_what)
void FileAccessNetworkClient : : lock_mutex ( ) {
2020-02-26 11:28:13 +01:00
mutex . lock ( ) ;
2014-02-10 02:10:30 +01:00
lockcount + + ;
}
void FileAccessNetworkClient : : unlock_mutex ( ) {
lockcount - - ;
2020-02-26 11:28:13 +01:00
mutex . unlock ( ) ;
2014-02-10 02:10:30 +01:00
}
void FileAccessNetworkClient : : put_32 ( int p_32 ) {
uint8_t buf [ 4 ] ;
encode_uint32 ( p_32 , buf ) ;
client - > put_data ( buf , 4 ) ;
DEBUG_PRINT ( " put32: " + itos ( p_32 ) ) ;
}
void FileAccessNetworkClient : : put_64 ( int64_t p_64 ) {
uint8_t buf [ 8 ] ;
encode_uint64 ( p_64 , buf ) ;
client - > put_data ( buf , 8 ) ;
DEBUG_PRINT ( " put64: " + itos ( p_64 ) ) ;
}
int FileAccessNetworkClient : : get_32 ( ) {
uint8_t buf [ 4 ] ;
client - > get_data ( buf , 4 ) ;
return decode_uint32 ( buf ) ;
}
int64_t FileAccessNetworkClient : : get_64 ( ) {
uint8_t buf [ 8 ] ;
client - > get_data ( buf , 8 ) ;
return decode_uint64 ( buf ) ;
}
void FileAccessNetworkClient : : _thread_func ( ) {
2018-01-30 16:22:15 +01:00
client - > set_no_delay ( true ) ;
2014-02-10 02:10:30 +01:00
while ( ! quit ) {
DEBUG_PRINT ( " SEM WAIT - " + itos ( sem - > get ( ) ) ) ;
2020-03-03 09:26:42 +01:00
sem . wait ( ) ;
2014-02-10 02:10:30 +01:00
DEBUG_TIME ( " sem_unlock " ) ;
//DEBUG_PRINT("semwait returned "+itos(werr));
DEBUG_PRINT ( " MUTEX LOCK " + itos ( lockcount ) ) ;
lock_mutex ( ) ;
DEBUG_PRINT ( " MUTEX PASS " ) ;
2020-02-26 11:28:13 +01:00
{
MutexLock lock ( blockrequest_mutex ) ;
while ( block_requests . size ( ) ) {
put_32 ( block_requests . front ( ) - > get ( ) . id ) ;
put_32 ( FileAccessNetwork : : COMMAND_READ_BLOCK ) ;
put_64 ( block_requests . front ( ) - > get ( ) . offset ) ;
put_32 ( block_requests . front ( ) - > get ( ) . size ) ;
block_requests . pop_front ( ) ;
}
2014-02-10 02:10:30 +01:00
}
DEBUG_PRINT ( " THREAD ITER " ) ;
DEBUG_TIME ( " sem_read " ) ;
int id = get_32 ( ) ;
int response = get_32 ( ) ;
DEBUG_PRINT ( " GET RESPONSE: " + itos ( response ) ) ;
2020-04-02 01:20:12 +02:00
FileAccessNetwork * fa = nullptr ;
2014-02-10 02:10:30 +01:00
if ( response ! = FileAccessNetwork : : RESPONSE_DATA ) {
2019-05-30 10:28:03 +02:00
if ( ! accesses . has ( id ) ) {
unlock_mutex ( ) ;
ERR_FAIL_COND ( ! accesses . has ( id ) ) ;
}
2014-02-10 02:10:30 +01:00
}
2020-05-14 16:41:43 +02:00
if ( accesses . has ( id ) ) {
2014-02-10 02:10:30 +01:00
fa = accesses [ id ] ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
switch ( response ) {
case FileAccessNetwork : : RESPONSE_OPEN : {
DEBUG_TIME ( " sem_open " ) ;
int status = get_32 ( ) ;
if ( status ! = OK ) {
fa - > _respond ( 0 , Error ( status ) ) ;
} else {
2019-03-26 18:51:13 +01:00
int64_t len = get_64 ( ) ;
2014-02-10 02:10:30 +01:00
fa - > _respond ( len , Error ( status ) ) ;
}
2020-03-03 09:26:42 +01:00
fa - > sem . post ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case FileAccessNetwork : : RESPONSE_DATA : {
int64_t offset = get_64 ( ) ;
2019-03-26 18:51:13 +01:00
int32_t len = get_32 ( ) ;
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
Vector < uint8_t > resp_block ;
resp_block . resize ( len ) ;
client - > get_data ( resp_block . ptrw ( ) , len ) ;
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( fa ) { //may have been queued
2022-09-29 11:53:28 +02:00
fa - > _set_block ( offset , resp_block ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
} break ;
case FileAccessNetwork : : RESPONSE_FILE_EXISTS : {
int status = get_32 ( ) ;
fa - > exists_modtime = status ! = 0 ;
2020-03-03 09:26:42 +01:00
fa - > sem . post ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case FileAccessNetwork : : RESPONSE_GET_MODTIME : {
uint64_t status = get_64 ( ) ;
fa - > exists_modtime = status ;
2020-03-03 09:26:42 +01:00
fa - > sem . post ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
}
unlock_mutex ( ) ;
}
}
void FileAccessNetworkClient : : _thread_func ( void * s ) {
2022-04-05 12:40:26 +02:00
FileAccessNetworkClient * self = static_cast < FileAccessNetworkClient * > ( s ) ;
2014-02-10 02:10:30 +01:00
self - > _thread_func ( ) ;
}
Error FileAccessNetworkClient : : connect ( const String & p_host , int p_port , const String & p_password ) {
2021-05-06 02:48:18 +02:00
IPAddress ip ;
2014-02-10 02:10:30 +01:00
if ( p_host . is_valid_ip_address ( ) ) {
ip = p_host ;
} else {
ip = IP : : get_singleton ( ) - > resolve_hostname ( p_host ) ;
}
DEBUG_PRINT ( " IP: " + String ( ip ) + " port " + itos ( p_port ) ) ;
2017-01-14 15:07:57 +01:00
Error err = client - > connect_to_host ( ip , p_port ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Cannot connect to host with IP: " + String ( ip ) + " and port: " + itos ( p_port ) ) ;
2014-02-10 02:10:30 +01:00
while ( client - > get_status ( ) = = StreamPeerTCP : : STATUS_CONNECTING ) {
//DEBUG_PRINT("trying to connect....");
OS : : get_singleton ( ) - > delay_usec ( 1000 ) ;
}
if ( client - > get_status ( ) ! = StreamPeerTCP : : STATUS_CONNECTED ) {
return ERR_CANT_CONNECT ;
}
2016-03-09 00:00:52 +01:00
CharString cs = p_password . utf8 ( ) ;
2014-02-10 02:10:30 +01:00
put_32 ( cs . length ( ) ) ;
client - > put_data ( ( const uint8_t * ) cs . ptr ( ) , cs . length ( ) ) ;
int e = get_32 ( ) ;
if ( e ! = OK ) {
return ERR_INVALID_PARAMETER ;
}
2021-01-19 13:29:41 +01:00
thread . start ( _thread_func , this ) ;
2014-02-10 02:10:30 +01:00
return OK ;
}
2020-04-02 01:20:12 +02:00
FileAccessNetworkClient * FileAccessNetworkClient : : singleton = nullptr ;
2014-02-10 02:10:30 +01:00
FileAccessNetworkClient : : FileAccessNetworkClient ( ) {
singleton = this ;
2021-06-18 00:03:09 +02:00
client . instantiate ( ) ;
2014-02-10 02:10:30 +01:00
}
FileAccessNetworkClient : : ~ FileAccessNetworkClient ( ) {
2021-01-19 13:29:41 +01:00
quit = true ;
sem . post ( ) ;
thread . wait_to_finish ( ) ;
2014-02-10 02:10:30 +01:00
}
2019-03-26 18:51:13 +01:00
void FileAccessNetwork : : _set_block ( uint64_t p_offset , const Vector < uint8_t > & p_block ) {
int32_t page = p_offset / page_size ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_INDEX ( page , pages . size ( ) ) ;
if ( page < pages . size ( ) - 1 ) {
ERR_FAIL_COND ( p_block . size ( ) ! = page_size ) ;
} else {
2019-03-26 18:51:13 +01:00
ERR_FAIL_COND ( ( uint64_t ) p_block . size ( ) ! = total_size % page_size ) ;
2014-02-10 02:10:30 +01:00
}
2020-02-26 11:28:13 +01:00
{
MutexLock lock ( buffer_mutex ) ;
pages . write [ page ] . buffer = p_block ;
pages . write [ page ] . queued = false ;
}
2014-02-10 02:10:30 +01:00
if ( waiting_on_page = = page ) {
waiting_on_page = - 1 ;
2020-03-03 09:26:42 +01:00
page_sem . post ( ) ;
2014-02-10 02:10:30 +01:00
}
}
2019-03-26 18:51:13 +01:00
void FileAccessNetwork : : _respond ( uint64_t p_len , Error p_status ) {
2014-02-10 02:10:30 +01:00
DEBUG_PRINT ( " GOT RESPONSE - len: " + itos ( p_len ) + " status: " + itos ( p_status ) ) ;
response = p_status ;
2020-05-14 16:41:43 +02:00
if ( response ! = OK ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
opened = true ;
total_size = p_len ;
2019-03-26 18:51:13 +01:00
int32_t pc = ( ( total_size - 1 ) / page_size ) + 1 ;
2014-02-10 02:10:30 +01:00
pages . resize ( pc ) ;
}
2022-09-05 13:01:31 +02:00
Error FileAccessNetwork : : open_internal ( const String & p_path , int p_mode_flags ) {
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND_V ( p_mode_flags ! = READ , ERR_UNAVAILABLE ) ;
2022-04-12 10:15:02 +02:00
_close ( ) ;
2014-02-10 02:10:30 +01:00
FileAccessNetworkClient * nc = FileAccessNetworkClient : : singleton ;
DEBUG_PRINT ( " open: " + p_path ) ;
DEBUG_TIME ( " open_begin " ) ;
nc - > lock_mutex ( ) ;
nc - > put_32 ( id ) ;
nc - > accesses [ id ] = this ;
nc - > put_32 ( COMMAND_OPEN_FILE ) ;
CharString cs = p_path . utf8 ( ) ;
nc - > put_32 ( cs . length ( ) ) ;
nc - > client - > put_data ( ( const uint8_t * ) cs . ptr ( ) , cs . length ( ) ) ;
pos = 0 ;
eof_flag = false ;
last_page = - 1 ;
2020-04-02 01:20:12 +02:00
last_page_buff = nullptr ;
2014-02-10 02:10:30 +01:00
2017-01-14 12:26:56 +01:00
//buffers.clear();
2014-02-10 02:10:30 +01:00
nc - > unlock_mutex ( ) ;
DEBUG_PRINT ( " OPEN POST " ) ;
DEBUG_TIME ( " open_post " ) ;
2020-03-03 09:26:42 +01:00
nc - > sem . post ( ) ; //awaiting answer
2014-02-10 02:10:30 +01:00
DEBUG_PRINT ( " WAIT... " ) ;
2020-03-03 09:26:42 +01:00
sem . wait ( ) ;
2014-02-10 02:10:30 +01:00
DEBUG_TIME ( " open_end " ) ;
DEBUG_PRINT ( " WAIT ENDED... " ) ;
return response ;
}
2022-04-12 10:15:02 +02:00
void FileAccessNetwork : : _close ( ) {
2020-05-14 16:41:43 +02:00
if ( ! opened ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
FileAccessNetworkClient * nc = FileAccessNetworkClient : : singleton ;
DEBUG_PRINT ( " CLOSE " ) ;
nc - > lock_mutex ( ) ;
nc - > put_32 ( id ) ;
nc - > put_32 ( COMMAND_CLOSE ) ;
pages . clear ( ) ;
opened = false ;
nc - > unlock_mutex ( ) ;
}
2020-05-14 14:29:06 +02:00
2014-02-10 02:10:30 +01:00
bool FileAccessNetwork : : is_open ( ) const {
return opened ;
}
2019-03-26 18:51:13 +01:00
void FileAccessNetwork : : seek ( uint64_t p_position ) {
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_MSG ( ! opened , " File must be opened before use. " ) ;
2019-03-26 18:51:13 +01:00
2014-02-10 02:10:30 +01:00
eof_flag = p_position > total_size ;
if ( p_position > = total_size ) {
p_position = total_size ;
}
pos = p_position ;
}
void FileAccessNetwork : : seek_end ( int64_t p_position ) {
seek ( total_size + p_position ) ;
}
2020-05-14 14:29:06 +02:00
2019-03-26 18:51:13 +01:00
uint64_t FileAccessNetwork : : get_position ( ) const {
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( ! opened , 0 , " File must be opened before use. " ) ;
2014-02-10 02:10:30 +01:00
return pos ;
}
2020-05-14 14:29:06 +02:00
2021-05-25 08:58:49 +02:00
uint64_t FileAccessNetwork : : get_length ( ) const {
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( ! opened , 0 , " File must be opened before use. " ) ;
2014-02-10 02:10:30 +01:00
return total_size ;
}
bool FileAccessNetwork : : eof_reached ( ) const {
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( ! opened , false , " File must be opened before use. " ) ;
2014-02-10 02:10:30 +01:00
return eof_flag ;
}
uint8_t FileAccessNetwork : : get_8 ( ) const {
uint8_t v ;
get_buffer ( & v , 1 ) ;
return v ;
}
2019-03-26 18:51:13 +01:00
void FileAccessNetwork : : _queue_page ( int32_t p_page ) const {
2020-05-14 16:41:43 +02:00
if ( p_page > = pages . size ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2020-12-15 13:04:21 +01:00
if ( pages [ p_page ] . buffer . is_empty ( ) & & ! pages [ p_page ] . queued ) {
2014-02-10 02:10:30 +01:00
FileAccessNetworkClient * nc = FileAccessNetworkClient : : singleton ;
2020-02-26 11:28:13 +01:00
{
MutexLock lock ( nc - > blockrequest_mutex ) ;
FileAccessNetworkClient : : BlockRequest br ;
br . id = id ;
2019-03-26 18:51:13 +01:00
br . offset = ( uint64_t ) p_page * page_size ;
2020-02-26 11:28:13 +01:00
br . size = page_size ;
nc - > block_requests . push_back ( br ) ;
pages . write [ p_page ] . queued = true ;
}
2014-02-10 02:10:30 +01:00
DEBUG_PRINT ( " QUEUE PAGE POST " ) ;
2020-03-03 09:26:42 +01:00
nc - > sem . post ( ) ;
2014-02-10 02:10:30 +01:00
DEBUG_PRINT ( " queued " + itos ( p_page ) ) ;
}
}
2019-03-26 18:51:13 +01:00
uint64_t FileAccessNetwork : : get_buffer ( uint8_t * p_dst , uint64_t p_length ) const {
2021-03-16 22:55:11 +01:00
ERR_FAIL_COND_V ( ! p_dst & & p_length > 0 , - 1 ) ;
2021-03-09 02:37:35 +01:00
2014-02-10 02:10:30 +01:00
if ( pos + p_length > total_size ) {
eof_flag = true ;
}
if ( pos + p_length > = total_size ) {
p_length = total_size - pos ;
}
uint8_t * buff = last_page_buff ;
2019-03-26 18:51:13 +01:00
for ( uint64_t i = 0 ; i < p_length ; i + + ) {
int32_t page = pos / page_size ;
2014-02-10 02:10:30 +01:00
if ( page ! = last_page ) {
2020-02-26 11:28:13 +01:00
buffer_mutex . lock ( ) ;
2020-12-15 13:04:21 +01:00
if ( pages [ page ] . buffer . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
waiting_on_page = page ;
2019-03-26 18:51:13 +01:00
for ( int32_t j = 0 ; j < read_ahead ; j + + ) {
2014-02-10 02:10:30 +01:00
_queue_page ( page + j ) ;
}
2020-02-26 11:28:13 +01:00
buffer_mutex . unlock ( ) ;
2014-02-10 02:10:30 +01:00
DEBUG_PRINT ( " wait " ) ;
2020-03-03 09:26:42 +01:00
page_sem . wait ( ) ;
2014-02-10 02:10:30 +01:00
DEBUG_PRINT ( " done " ) ;
} else {
2019-03-26 18:51:13 +01:00
for ( int32_t j = 0 ; j < read_ahead ; j + + ) {
2014-02-10 02:10:30 +01:00
_queue_page ( page + j ) ;
}
2020-02-26 11:28:13 +01:00
buffer_mutex . unlock ( ) ;
2014-02-10 02:10:30 +01:00
}
2018-07-25 03:11:03 +02:00
buff = pages . write [ page ] . buffer . ptrw ( ) ;
2014-02-10 02:10:30 +01:00
last_page_buff = buff ;
last_page = page ;
}
p_dst [ i ] = buff [ pos - uint64_t ( page ) * page_size ] ;
pos + + ;
}
return p_length ;
}
Error FileAccessNetwork : : get_error ( ) const {
return pos = = total_size ? ERR_FILE_EOF : OK ;
}
2017-09-22 07:56:02 +02:00
void FileAccessNetwork : : flush ( ) {
ERR_FAIL ( ) ;
}
2014-02-10 02:10:30 +01:00
void FileAccessNetwork : : store_8 ( uint8_t p_dest ) {
ERR_FAIL ( ) ;
}
bool FileAccessNetwork : : file_exists ( const String & p_path ) {
FileAccessNetworkClient * nc = FileAccessNetworkClient : : singleton ;
nc - > lock_mutex ( ) ;
nc - > put_32 ( id ) ;
nc - > put_32 ( COMMAND_FILE_EXISTS ) ;
CharString cs = p_path . utf8 ( ) ;
nc - > put_32 ( cs . length ( ) ) ;
nc - > client - > put_data ( ( const uint8_t * ) cs . ptr ( ) , cs . length ( ) ) ;
nc - > unlock_mutex ( ) ;
DEBUG_PRINT ( " FILE EXISTS POST " ) ;
2020-03-03 09:26:42 +01:00
nc - > sem . post ( ) ;
sem . wait ( ) ;
2014-02-10 02:10:30 +01:00
return exists_modtime ! = 0 ;
}
uint64_t FileAccessNetwork : : _get_modified_time ( const String & p_file ) {
FileAccessNetworkClient * nc = FileAccessNetworkClient : : singleton ;
nc - > lock_mutex ( ) ;
nc - > put_32 ( id ) ;
nc - > put_32 ( COMMAND_GET_MODTIME ) ;
CharString cs = p_file . utf8 ( ) ;
nc - > put_32 ( cs . length ( ) ) ;
nc - > client - > put_data ( ( const uint8_t * ) cs . ptr ( ) , cs . length ( ) ) ;
nc - > unlock_mutex ( ) ;
DEBUG_PRINT ( " MODTIME POST " ) ;
2020-03-03 09:26:42 +01:00
nc - > sem . post ( ) ;
sem . wait ( ) ;
2014-02-10 02:10:30 +01:00
return exists_modtime ;
}
2019-04-07 20:46:52 +02:00
uint32_t FileAccessNetwork : : _get_unix_permissions ( const String & p_file ) {
2019-06-03 14:20:43 +02:00
ERR_PRINT ( " Getting UNIX permissions from network drives is not implemented yet " ) ;
2019-04-07 20:46:52 +02:00
return 0 ;
}
Error FileAccessNetwork : : _set_unix_permissions ( const String & p_file , uint32_t p_permissions ) {
2019-06-03 14:20:43 +02:00
ERR_PRINT ( " Setting UNIX permissions on network drives is not implemented yet " ) ;
return ERR_UNAVAILABLE ;
2019-04-07 20:46:52 +02:00
}
2017-01-05 13:16:00 +01:00
void FileAccessNetwork : : configure ( ) {
2022-11-08 19:53:22 +01:00
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " network/remote_fs/page_size " , PROPERTY_HINT_RANGE , " 1,65536,1,or_greater " ) , 65536 ) ; // Is used as denominator and can't be zero
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " network/remote_fs/page_read_ahead " , PROPERTY_HINT_RANGE , " 0,8,1,or_greater " ) , 4 ) ;
2017-01-05 13:16:00 +01:00
}
2014-02-10 02:10:30 +01:00
FileAccessNetwork : : FileAccessNetwork ( ) {
FileAccessNetworkClient * nc = FileAccessNetworkClient : : singleton ;
nc - > lock_mutex ( ) ;
id = nc - > last_id + + ;
nc - > accesses [ id ] = this ;
nc - > unlock_mutex ( ) ;
2017-01-05 13:16:00 +01:00
page_size = GLOBAL_GET ( " network/remote_fs/page_size " ) ;
read_ahead = GLOBAL_GET ( " network/remote_fs/page_read_ahead " ) ;
2014-02-10 02:10:30 +01:00
}
FileAccessNetwork : : ~ FileAccessNetwork ( ) {
2022-04-12 10:15:02 +02:00
_close ( ) ;
2014-02-10 02:10:30 +01:00
FileAccessNetworkClient * nc = FileAccessNetworkClient : : singleton ;
nc - > lock_mutex ( ) ;
nc - > accesses . erase ( id ) ;
nc - > unlock_mutex ( ) ;
}