2023-11-29 18:47:11 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "UbaStorageServer.h"
2024-04-05 19:10:53 -04:00
# include "UbaFileAccessor.h"
2023-11-29 18:47:11 -05:00
# include "UbaNetworkServer.h"
# include "UbaTrace.h"
namespace uba
{
2024-06-14 02:35:27 -04:00
void StorageServerCreateInfo : : Apply ( Config & config )
{
StorageCreateInfo : : Apply ( config ) ;
}
2023-11-29 18:47:11 -05:00
StorageServer : : StorageServer ( const StorageServerCreateInfo & info )
: StorageImpl ( info , TC ( " UbaStorageServer " ) )
, m_server ( info . server )
{
m_zone = info . zone ;
2024-04-10 20:29:18 -04:00
m_allowFallback = info . allowFallback ;
2024-04-05 19:10:53 -04:00
m_writeRecievedCasFilesToDisk = info . writeRecievedCasFilesToDisk ;
2023-11-29 18:47:11 -05:00
if ( ! CreateGuid ( m_uid ) )
UBA_ASSERT ( false ) ;
m_server . RegisterService ( ServiceId ,
2024-03-03 21:30:10 -05:00
[ this ] ( const ConnectionInfo & connectionInfo , MessageInfo & messageInfo , BinaryReader & reader , BinaryWriter & writer )
2023-11-29 18:47:11 -05:00
{
2024-03-03 21:30:10 -05:00
return HandleMessage ( connectionInfo , messageInfo . type , reader , writer ) ;
2023-11-29 18:47:11 -05:00
} ,
[ ] ( u8 messageType )
{
return ToString ( StorageMessageType ( messageType ) ) ;
}
) ;
m_server . RegisterOnClientConnected ( ServiceId , [ this ] ( const Guid & clientUid , u32 clientId )
{
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_loadCasTableLock , lock ) ;
2023-11-29 18:47:11 -05:00
if ( ! m_casTableLoaded )
LoadCasTable ( true ) ;
} ) ;
m_server . RegisterOnClientDisconnected ( ServiceId , [ this ] ( const Guid & clientUid , u32 clientId )
{
OnDisconnected ( clientId ) ;
} ) ;
}
StorageServer : : ~ StorageServer ( )
{
2024-06-05 14:00:34 -04:00
WaitForActiveWork ( ) ;
2023-11-29 18:47:11 -05:00
UBA_ASSERT ( m_waitEntries . empty ( ) ) ;
UBA_ASSERT ( m_proxies . empty ( ) ) ;
m_server . UnregisterOnClientDisconnected ( ServiceId ) ;
m_server . UnregisterService ( ServiceId ) ;
}
2023-12-05 19:02:30 -05:00
bool StorageServer : : RegisterDisallowedPath ( const tchar * path )
{
m_disallowedPaths . push_back ( path ) ;
return true ;
}
2024-06-05 14:00:34 -04:00
void StorageServer : : WaitForActiveWork ( )
{
while ( m_activeUnmap )
Sleep ( 5 ) ;
}
2023-11-29 18:47:11 -05:00
bool StorageServer : : GetZone ( StringBufferBase & out )
{
if ( m_zone . empty ( ) )
return false ;
out . Append ( m_zone ) ;
return true ;
}
bool StorageServer : : RetrieveCasFile ( RetrieveResult & out , const CasKey & casKey , const tchar * hint , FileMappingBuffer * mappingBuffer , u64 memoryMapAlignment , bool allowProxy )
{
UBA_ASSERT ( ! mappingBuffer ) ;
2023-12-06 01:37:11 -05:00
UBA_ASSERT ( casKey ! = CasKeyZero ) ;
2023-11-29 18:47:11 -05:00
out . casKey = casKey ;
out . size = InvalidValue ;
CasKey actualKey = casKey ;
if ( m_storeCompressed )
actualKey = AsCompressed ( casKey , true ) ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_waitEntriesLock , waitLock ) ;
2023-11-29 18:47:11 -05:00
WaitEntry & waitEntry = m_waitEntries [ actualKey ] ;
+ + waitEntry . refCount ;
waitLock . Leave ( ) ;
auto g = MakeGuard ( [ & ] ( )
{
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_waitEntriesLock , waitLock2 ) ;
2023-11-29 18:47:11 -05:00
if ( ! - - waitEntry . refCount )
m_waitEntries . erase ( actualKey ) ;
} ) ;
if ( HasCasFile ( actualKey ) )
return true ;
u64 startTime = GetTime ( ) ;
u32 timeout = 0 ;
2024-07-24 02:26:22 -04:00
while ( ! waitEntry . done . IsSet ( timeout ) ) // TODO WaitMultipleObjects (additional work and Done)
2023-11-29 18:47:11 -05:00
{
timeout = m_server . DoAdditionalWork ( ) ? 0 : 50 ;
u64 waited = GetTime ( ) - startTime ;
if ( TimeToMs ( waited ) > 4 * 60 * 1000 ) // 4 minutes timeout
2024-03-03 21:30:10 -05:00
{
m_logger . Info ( TC ( " Timed out waiting %s for cas %s to be transferred from remote to storage (%s) " ) , TimeToText ( waited ) . str , CasKeyString ( casKey ) . str , hint ) ;
return false ;
}
2023-11-29 18:47:11 -05:00
}
return waitEntry . Success ;
}
2024-02-19 01:59:59 -05:00
void StorageServer : : ActiveFetch : : Release ( StorageServer & server , const tchar * reason )
{
if ( mappedView . handle . IsValid ( ) )
{
if ( ownsMapping )
{
2024-06-05 14:00:34 -04:00
+ + server . m_activeUnmap ;
server . GetServer ( ) . AddWork ( [ & server , mb = memoryBegin , mp = mappedView , rfh = readFileHandle ] ( )
{
UnmapViewOfFile ( mb , mp . size , TC ( " " ) ) ;
CloseFileMapping ( mp . handle ) ;
CloseFile ( nullptr , rfh ) ;
- - server . m_activeUnmap ;
} , 1 , TC ( " ActiveFetchRelease " ) ) ;
2024-02-19 01:59:59 -05:00
}
else
server . m_casDataBuffer . UnmapView ( mappedView , TC ( " OnDisconnected " ) ) ;
}
else
2024-08-21 02:51:44 -04:00
{
if ( ! memoryBegin )
server . m_logger . Warning ( TC ( " This should not happen. It means there is a race between a fetch and a disconnect. Report to honk (%s) " ) , reason ) ;
2024-04-10 20:29:18 -04:00
server . m_bufferSlots . Push ( memoryBegin ) ;
2024-08-21 02:51:44 -04:00
memoryBegin = nullptr ;
}
2024-02-19 01:59:59 -05:00
}
2023-11-29 18:47:11 -05:00
void StorageServer : : OnDisconnected ( u32 clientId )
{
{
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_proxiesLock , lock ) ;
2023-11-29 18:47:11 -05:00
for ( auto it = m_proxies . begin ( ) ; it ! = m_proxies . end ( ) ; + + it )
{
ProxyEntry & e = it - > second ;
if ( e . clientId ! = clientId )
continue ;
2024-02-22 18:46:44 -05:00
m_logger . Detail ( TC ( " Proxy %s:%u for zone %s removed " ) , e . host . c_str ( ) , e . port , e . zone . c_str ( ) ) ;
2023-11-29 18:47:11 -05:00
m_proxies . erase ( it ) ;
break ;
}
}
{
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_activeStoresLock , lock ) ;
2023-11-29 18:47:11 -05:00
for ( auto it = m_activeStores . begin ( ) ; it ! = m_activeStores . end ( ) ; )
{
ActiveStore & store = it - > second ;
if ( store . clientId ! = clientId )
{
+ + it ;
continue ;
}
{
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( store . casEntry - > lock , entryLock ) ;
2023-11-29 18:47:11 -05:00
store . casEntry - > verified = false ;
store . casEntry - > beingWritten = false ;
2023-12-12 21:25:58 -05:00
if ( m_traceStore )
m_trace - > FileEndStore ( clientId , store . casEntry - > key ) ;
2023-11-29 18:47:11 -05:00
}
2024-04-24 20:07:13 -04:00
if ( auto fa = store . fileAccessor )
{
const tchar * filename = fa - > GetFileName ( ) ;
delete store . fileAccessor ;
free ( ( void * ) filename ) ;
}
2024-04-05 19:10:53 -04:00
2023-11-29 18:47:11 -05:00
m_casDataBuffer . UnmapView ( store . mappedView , TC ( " OnDisconnected " ) ) ;
it = m_activeStores . erase ( it ) ;
}
}
{
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_activeFetchesLock , lock ) ;
2023-11-29 18:47:11 -05:00
for ( auto it = m_activeFetches . begin ( ) ; it ! = m_activeFetches . end ( ) ; )
{
ActiveFetch & fetch = it - > second ;
if ( fetch . clientId ! = clientId )
{
+ + it ;
continue ;
}
2024-07-24 18:51:02 -04:00
m_logger . Detail ( TC ( " Cancelled fetch id %u because of disconnect of client with id %u " ) , u32 ( it - > first ) , clientId ) ;
2024-02-19 01:59:59 -05:00
fetch . Release ( * this , TC ( " OnDisconnected " ) ) ;
2023-11-29 18:47:11 -05:00
2023-12-12 21:25:58 -05:00
if ( m_traceFetch )
m_trace - > FileEndFetch ( clientId , AsCompressed ( fetch . casKey , m_storeCompressed ) ) ;
2023-11-29 18:47:11 -05:00
it = m_activeFetches . erase ( it ) ;
}
}
}
bool StorageServer : : StoreCasFile ( CasKey & out , StringKey fileNameKey , const tchar * fileName , FileMappingHandle mappingHandle , u64 mappingOffset , u64 fileSize , const tchar * hint , bool deferCreation , bool keepMappingInMemory )
{
u8 * fileMem = MapViewOfFile ( mappingHandle , FILE_MAP_READ , mappingOffset , fileSize ) ;
UBA_ASSERT ( fileMem ) ;
2024-02-09 16:12:12 -05:00
auto memClose = MakeGuard ( [ & ] ( ) { UnmapViewOfFile ( fileMem , fileSize , fileName ) ; } ) ;
2023-11-29 18:47:11 -05:00
bool storeCompressed = true ;
out = CalculateCasKey ( fileMem , fileSize , storeCompressed ) ;
if ( out = = CasKeyZero )
return false ;
2024-06-04 14:07:46 -04:00
FileEntry & fileEntry = GetOrCreateFileEntry ( fileNameKey ) ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( fileEntry . lock , entryLock ) ;
2023-11-29 18:47:11 -05:00
fileEntry . verified = true ;
fileEntry . casKey = out ;
fileEntry . size = fileSize ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_externalFileMappingsLock , externalFileLock ) ;
2023-11-29 18:47:11 -05:00
m_externalFileMappings . try_emplace ( fileNameKey , ExternalFileMapping { mappingHandle , mappingOffset , fileSize } ) ;
externalFileLock . Leave ( ) ;
2024-04-25 13:10:20 -04:00
bool fileIsCompressed = false ;
2024-05-31 02:18:27 -04:00
if ( ! AddCasFile ( fileNameKey , fileName , fileEntry . casKey , deferCreation , fileIsCompressed ) )
2023-11-29 18:47:11 -05:00
return false ;
return true ;
}
bool StorageServer : : WriteCompressed ( WriteResult & out , const tchar * from , const tchar * toFile )
{
StringBuffer < > fromForKey ;
fromForKey . Append ( from ) ;
if ( CaseInsensitiveFs )
fromForKey . MakeLower ( ) ;
StringKey fileNameKey = ToStringKey ( fromForKey ) ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_externalFileMappingsLock , lock ) ;
2023-11-29 18:47:11 -05:00
auto findIt = m_externalFileMappings . find ( fileNameKey ) ;
if ( findIt = = m_externalFileMappings . end ( ) )
{
lock . Leave ( ) ;
return StorageImpl : : WriteCompressed ( out , from , toFile ) ;
}
ExternalFileMapping & mapping = findIt - > second ;
lock . Leave ( ) ;
u8 * fileMem = MapViewOfFile ( mapping . mappingHandle , FILE_MAP_READ , mapping . mappingOffset , mapping . fileSize ) ;
UBA_ASSERT ( fileMem ) ;
2024-02-09 16:12:12 -05:00
auto memClose = MakeGuard ( [ & ] ( ) { UnmapViewOfFile ( fileMem , mapping . fileSize , from ) ; } ) ;
2024-04-25 13:10:20 -04:00
return StorageImpl : : WriteCompressed ( out , from , InvalidFileHandle , fileMem , mapping . fileSize , toFile , nullptr , 0 ) ;
2023-11-29 18:47:11 -05:00
}
2023-12-05 19:02:30 -05:00
bool StorageServer : : IsDisallowedPath ( const tchar * fileName )
{
for ( auto & path : m_disallowedPaths )
if ( StartsWith ( fileName , path . c_str ( ) ) )
return true ;
return false ;
}
2023-11-29 18:47:11 -05:00
void StorageServer : : SetTrace ( Trace * trace , bool detailed )
{
m_trace = trace ;
m_traceFetch = detailed ;
m_traceStore = detailed ;
}
2024-03-08 18:31:48 -05:00
bool StorageServer : : HasProxy ( u32 clientId )
{
SCOPED_READ_LOCK ( m_proxiesLock , l ) ;
for ( auto & kv : m_proxies )
if ( kv . second . clientId = = clientId )
return true ;
return false ;
}
2024-07-30 13:47:15 -04:00
bool StorageServer : : WaitForWritten ( CasEntry & casEntry , ScopedWriteLock & entryLock , const ConnectionInfo & connectionInfo , const tchar * hint )
2023-11-29 18:47:11 -05:00
{
int waitCount = 0 ;
while ( true )
{
if ( ! casEntry . beingWritten )
return true ;
2024-07-30 13:47:15 -04:00
CasKey key = casEntry . key ;
2023-11-29 18:47:11 -05:00
entryLock . Leave ( ) ;
Sleep ( 100 ) ;
entryLock . Enter ( ) ;
2024-07-30 13:47:15 -04:00
if ( + + waitCount < 12 * 60 * 10 )
continue ;
// Something went wrong.. should not take 12 minutes to write a file
SCOPED_READ_LOCK ( m_activeStoresLock , activeLock ) ;
for ( auto & kv : m_activeStores )
2023-11-29 18:47:11 -05:00
{
2024-07-30 13:47:15 -04:00
if ( kv . second . casEntry ! = & casEntry )
continue ;
ActiveStore & as = kv . second ;
return m_logger . Error ( TC ( " Client %u waited more than 12 minutes for file %s (%s) to be written by client %u (Written %llu/%llu) " ) , connectionInfo . GetId ( ) , CasKeyString ( key ) . str , hint , as . clientId , as . totalWritten . load ( ) , as . fileSize ) ;
2023-11-29 18:47:11 -05:00
}
2024-07-30 13:47:15 -04:00
return m_logger . Error ( TC ( " Client %u waited more than 12 minutes for file %s (%s) to be written but there are no active writes. This should not be possible! " ) , connectionInfo . GetId ( ) , CasKeyString ( key ) . str , hint ) ;
2023-11-29 18:47:11 -05:00
}
}
bool StorageServer : : HandleMessage ( const ConnectionInfo & connectionInfo , u8 messageType , BinaryReader & reader , BinaryWriter & writer )
{
ActiveStore * firstStore = nullptr ;
ActiveStore tempStore ;
switch ( messageType )
{
case StorageMessageType_Connect :
{
StringBuffer < > clientName ;
reader . ReadString ( clientName ) ;
u32 clientVersion = reader . ReadU32 ( ) ;
if ( clientVersion ! = StorageNetworkVersion )
return m_logger . Error ( TC ( " Different network versions. Client: %u, Server: %u. Disconnecting " ) , clientVersion , StorageNetworkVersion ) ;
if ( reader . ReadBool ( ) ) // is proxy
return m_logger . Error ( TC ( " Proxy is sending connect message. This path is not implemented " ) ) ;
u16 proxyPort = reader . ReadU16 ( ) ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_connectionInfoLock , lock ) ;
2023-11-29 18:47:11 -05:00
Info & info = m_connectionInfo [ connectionInfo . GetId ( ) ] ;
info . zone = reader . ReadString ( ) ;
info . storageSize = reader . ReadU64 ( ) ;
info . internalAddress = reader . ReadString ( ) ;
info . proxyPort = proxyPort ;
writer . WriteGuid ( m_uid ) ;
2024-04-10 20:29:18 -04:00
writer . WriteByte ( m_casCompressor ) ;
writer . WriteByte ( m_casCompressionLevel ) ;
2023-11-29 18:47:11 -05:00
return true ;
}
case StorageMessageType_FetchBegin :
{
2024-07-22 18:34:54 -04:00
// TODO: Remove this when we have tracked down the issue where clients time out
u32 todoRemoveMe = 0 ;
auto timeoutGuard = MakeGuard ( [ & , timeoutStartTime = GetTime ( ) ] ( )
{
u64 timeSpentMs = TimeToMs ( GetTime ( ) - timeoutStartTime ) ;
if ( timeSpentMs > 8 * 60 * 1000 )
{
// Took more than 5 minutes to respond
m_logger . Warning ( TC ( " Took more than 8 minutes to respond to FetchBegin (%u).. is this some sort of hang or just host being half dead? " ) , todoRemoveMe ) ;
}
} ) ;
2023-11-29 18:47:11 -05:00
if ( reader . ReadBool ( ) ) // Wants proxy
{
2024-07-22 18:34:54 -04:00
todoRemoveMe = 1 ;
2024-02-26 01:14:42 -05:00
SCOPED_READ_LOCK ( m_connectionInfoLock , lock ) ;
2023-11-29 18:47:11 -05:00
auto findIt = m_connectionInfo . find ( connectionInfo . GetId ( ) ) ;
UBA_ASSERT ( findIt ! = m_connectionInfo . end ( ) ) ;
Info & info = findIt - > second ;
lock . Leave ( ) ;
if ( ! info . zone . empty ( ) )
{
// Zone logic is a bit special to be able to handle AWS setups.
// AWS has zones named a,b,c etc in the end. us-east-1a, us-east-1b etc.
// If host is also in AWS, then we want different proxies per zone but if host is not in AWS, we want one proxy for all zones in a region
StringBuffer < 256 > proxyName ;
if ( ! m_zone . empty ( ) & & info . zone . size ( ) = = m_zone . size ( ) & & Equals ( m_zone . c_str ( ) , info . zone . c_str ( ) , u64 ( m_zone . size ( ) - 1 ) ) )
{
// Host is inside AWS and same region.... if aws availability zone is different than host, then we use proxy
if ( m_zone ! = info . zone )
proxyName . Append ( info . zone . c_str ( ) ) ;
}
else if ( m_zone ! = info . zone )
{
// We remove last character from zone to make sure all AWS availability zones in the same region use same proxy if host zone is outside AWS
proxyName . Append ( info . zone . c_str ( ) , info . zone . size ( ) - 1 ) ;
}
if ( ! proxyName . IsEmpty ( ) )
{
writer . WriteU16 ( u16 ( ~ 0 ) ) ;
writer . Write7BitEncoded ( 0 ) ;
writer . WriteByte ( 1 < < 2 ) ;
auto proxyKey = ToStringKeyNoCheck ( proxyName . data , proxyName . count ) ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_proxiesLock , proxiesLock ) ;
2023-11-29 18:47:11 -05:00
ProxyEntry & proxy = m_proxies [ proxyKey ] ;
if ( proxy . clientId = = ~ 0u )
{
proxy . clientId = connectionInfo . GetId ( ) ;
proxy . host = info . internalAddress ;
proxy . port = info . proxyPort ;
proxy . zone = proxyName . data ;
2024-02-22 18:46:44 -05:00
m_logger . Detail ( TC ( " %s:%u (%s) is assigned as proxy for zone %s " ) , proxy . host . c_str ( ) , proxy . port , GuidToString ( connectionInfo . GetUid ( ) ) . str , proxy . zone . c_str ( ) ) ;
2023-11-29 18:47:11 -05:00
writer . WriteBool ( true ) ;
writer . WriteU16 ( info . proxyPort ) ;
if ( m_trace )
m_trace - > ProxyCreated ( proxy . clientId , proxyName . data ) ;
}
else
{
2024-03-03 23:44:00 -05:00
const tchar * proxyHost = proxy . host . c_str ( ) ;
if ( connectionInfo . GetId ( ) = = proxy . clientId )
proxyHost = TC ( " inprocess " ) ;
2023-11-29 18:47:11 -05:00
writer . WriteBool ( false ) ;
2024-03-03 23:44:00 -05:00
writer . WriteString ( proxyHost ) ;
2023-11-29 18:47:11 -05:00
writer . WriteU16 ( proxy . port ) ;
if ( m_trace )
m_trace - > ProxyUsed ( connectionInfo . GetId ( ) , proxyName . data ) ;
}
return true ;
}
}
}
2024-07-22 18:34:54 -04:00
todoRemoveMe = 2 ;
2023-11-29 18:47:11 -05:00
u64 start = GetTime ( ) ;
CasKey casKey = reader . ReadCasKey ( ) ;
StringBuffer < > hint ;
reader . ReadString ( hint ) ;
casKey = AsCompressed ( casKey , m_storeCompressed ) ;
CasEntry * casEntry = nullptr ;
bool has = HasCasFile ( casKey , & casEntry ) ; // HasCasFile also writes deferred cas entries if in queue
2024-04-10 20:29:18 -04:00
if ( ! has )
2023-11-29 18:47:11 -05:00
{
2024-07-22 18:34:54 -04:00
todoRemoveMe = 3 ;
2024-04-10 20:29:18 -04:00
if ( ! EnsureCasFile ( casKey , nullptr ) & & m_allowFallback )
{
// Last resort.. use hint to load file into cas (hint should be renamed since it is now a critical parameter)
// We better check the caskey first to make sure it is matching on the server
2023-11-29 18:47:11 -05:00
2024-05-31 02:18:27 -04:00
StringKey fileNameKey = CaseInsensitiveFs ? ToStringKeyLower ( hint ) : ToStringKey ( hint ) ;
2024-04-10 20:29:18 -04:00
CasKey checkedCasKey ;
2023-11-29 18:47:11 -05:00
{
2024-04-10 20:29:18 -04:00
SCOPED_READ_LOCK ( m_fileTableLookupLock , lookupLock ) ;
auto findIt = m_fileTableLookup . find ( fileNameKey ) ;
if ( findIt ! = m_fileTableLookup . end ( ) )
{
FileEntry & fileEntry = findIt - > second ;
lookupLock . Leave ( ) ;
SCOPED_READ_LOCK ( fileEntry . lock , entryLock ) ;
if ( fileEntry . verified )
checkedCasKey = fileEntry . casKey ;
}
2023-11-29 18:47:11 -05:00
}
2024-04-10 20:29:18 -04:00
if ( checkedCasKey = = CasKeyZero )
2023-11-29 18:47:11 -05:00
{
2024-04-10 20:29:18 -04:00
m_logger . Info ( TC ( " Server did not find cas for %s in file table lookup. Recalculating cas key " ) , hint . data ) ;
if ( ! CalculateCasKey ( checkedCasKey , hint . data ) )
{
m_logger . Error ( TC ( " FetchBegin failed for cas file %s (%s) requested by %s. Can't calculate cas key for file " ) , CasKeyString ( casKey ) . str , hint . data , GuidToString ( connectionInfo . GetUid ( ) ) . str ) ;
writer . WriteU16 ( 0 ) ;
return false ;
}
}
2024-05-24 17:45:03 -04:00
if ( AsCompressed ( checkedCasKey , m_storeCompressed ) ! = casKey )
2024-04-10 20:29:18 -04:00
{
2024-05-17 14:00:34 -04:00
m_logger . Error ( TC ( " FetchBegin failed for cas file %s (%s). File on disk has different cas %s " ) , CasKeyString ( casKey ) . str , hint . data , CasKeyString ( checkedCasKey ) . str ) ;
2023-11-29 18:47:11 -05:00
writer . WriteU16 ( 0 ) ;
return false ;
}
2024-04-25 13:10:20 -04:00
bool deferCreation = false ;
bool fileIsCompressed = false ;
2024-05-31 02:18:27 -04:00
if ( ! AddCasFile ( fileNameKey , hint . data , casKey , deferCreation , fileIsCompressed ) )
2024-04-10 20:29:18 -04:00
{
m_logger . Error ( TC ( " FetchBegin failed for cas file %s (%s). Can't add cas file to database " ) , CasKeyString ( casKey ) . str , hint . data ) ;
writer . WriteU16 ( 0 ) ;
return true ;
}
2023-11-29 18:47:11 -05:00
}
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_casLookupLock , lookupLock ) ;
2023-11-29 18:47:11 -05:00
auto findIt = m_casLookup . find ( casKey ) ;
2024-04-10 20:29:18 -04:00
if ( findIt = = m_casLookup . end ( ) )
{
writer . WriteU16 ( 0 ) ;
return true ;
}
2023-11-29 18:47:11 -05:00
casEntry = & findIt - > second ;
}
2024-07-22 18:34:54 -04:00
todoRemoveMe = 4 ;
2023-12-05 19:02:30 -05:00
if ( casEntry - > disallowed )
{
writer . WriteU16 ( 0 ) ;
m_logger . Error ( TC ( " Client is asking for cas content of file that is not allowed to be transferred. (%s) " ) , hint . data ) ;
return true ;
}
2024-02-19 01:59:59 -05:00
StringBuffer < 512 > casFile ;
2023-11-29 18:47:11 -05:00
FileHandle readFileHandle = InvalidFileHandle ;
2023-12-12 21:25:58 -05:00
auto rfg = MakeGuard ( [ & ] ( ) { CloseFile ( nullptr , readFileHandle ) ; } ) ;
2023-11-29 18:47:11 -05:00
u64 fileSize ;
u8 * memoryBegin = nullptr ;
u8 * memoryPos = nullptr ;
2024-02-19 01:59:59 -05:00
bool ownsMapping = false ;
2023-11-29 18:47:11 -05:00
MappedView mappedView ;
auto mvg = MakeGuard ( [ & ] ( ) { m_casDataBuffer . UnmapView ( mappedView , TC ( " FetchBegin " ) ) ; } ) ;
2024-07-22 18:34:54 -04:00
todoRemoveMe = 5 ;
2023-11-29 18:47:11 -05:00
bool useFileMapping = casEntry - > mappingHandle . IsValid ( ) ;
if ( useFileMapping )
{
mappedView = m_casDataBuffer . MapView ( casEntry - > mappingHandle , casEntry - > mappingOffset , casEntry - > mappingSize , CasKeyString ( casKey ) . str ) ;
memoryBegin = mappedView . memory ;
fileSize = casEntry - > mappingSize ;
if ( ! memoryBegin )
return m_logger . Error ( TC ( " Failed to map memory map for %s. Will use file handle instead (%s) " ) , CasKeyString ( casKey ) . str , LastErrorToText ( ) . data ) ;
memoryPos = memoryBegin ;
}
else
{
# if !UBA_USE_SPARSEFILE
GetCasFileName ( casFile , casKey ) ;
if ( ! OpenFileSequentialRead ( m_logger , casFile . data , readFileHandle ) )
{
writer . WriteU16 ( 0 ) ;
return true ;
}
if ( ! uba : : GetFileSizeEx ( fileSize , readFileHandle ) )
return m_logger . Error ( TC ( " GetFileSizeEx failed on file %s (%s) " ) , casFile . data , LastErrorToText ( ) . data ) ;
# else
UBA_ASSERT ( false ) ;
# endif
2024-02-19 01:59:59 -05:00
if ( fileSize > BufferSlotSize )
{
mappedView . handle = CreateFileMappingW ( readFileHandle , PAGE_READONLY , fileSize , TC ( " " ) ) ;
if ( ! mappedView . handle . IsValid ( ) )
return m_logger . Error ( TC ( " Failed to create file mapping of %s (%s) " ) , casFile . data , LastErrorToText ( ) . data ) ;
u64 offset = memoryPos - memoryBegin ;
mappedView . memory = MapViewOfFile ( mappedView . handle , FILE_MAP_READ , 0 , fileSize ) ;
if ( ! mappedView . memory )
return m_logger . Error ( TC ( " Failed to map memory of %s (%s) " ) , casFile . data , LastErrorToText ( ) . data ) ;
memoryBegin = mappedView . memory ;
memoryPos = memoryBegin + offset ;
ownsMapping = true ;
useFileMapping = true ;
}
2023-11-29 18:47:11 -05:00
}
2024-07-22 18:34:54 -04:00
todoRemoveMe = 6 ;
2023-11-29 18:47:11 -05:00
if ( m_trace )
m_trace - > FileBeginFetch ( connectionInfo . GetId ( ) , casKey , fileSize , hint . data , m_traceFetch ) ;
auto cg = MakeGuard ( [ & ] ( ) { if ( m_traceFetch ) m_trace - > FileEndFetch ( connectionInfo . GetId ( ) , casKey ) ; } ) ;
u64 left = fileSize ;
u16 * fetchId = ( u16 * ) writer . AllocWrite ( sizeof ( u16 ) ) ;
* fetchId = 0 ;
writer . Write7BitEncoded ( fileSize ) ;
u8 flags = 0 ;
flags | = u8 ( m_storeCompressed ) < < 0 ;
flags | = u8 ( m_traceFetch ) < < 1 ;
writer . WriteByte ( flags ) ;
u64 capacityLeft = writer . GetCapacityLeft ( ) ;
u32 toWrite = u32 ( Min ( left , capacityLeft ) ) ;
void * writeBuffer = writer . AllocWrite ( toWrite ) ;
2024-07-22 18:34:54 -04:00
todoRemoveMe = 7 ;
2023-11-29 18:47:11 -05:00
if ( useFileMapping )
{
memcpy ( writeBuffer , memoryPos , toWrite ) ;
memoryPos + = toWrite ;
}
else if ( toWrite = = left )
{
2024-02-19 01:59:59 -05:00
if ( ! ReadFile ( m_logger , casFile . data , readFileHandle , writeBuffer , toWrite ) )
2023-11-29 18:47:11 -05:00
{
UBA_ASSERT ( false ) ; // Implement
2024-08-21 02:51:44 -04:00
return m_logger . Error ( TC ( " Failed to read file %s (%s) (1) " ) , casFile . data , LastErrorToText ( ) . data ) ; ;
2023-11-29 18:47:11 -05:00
}
}
else
{
2024-04-10 20:29:18 -04:00
memoryBegin = m_bufferSlots . Pop ( ) ;
2023-11-29 18:47:11 -05:00
memoryPos = memoryBegin ;
u32 toRead = u32 ( Min ( left , BufferSlotSize ) ) ;
2024-02-19 01:59:59 -05:00
if ( ! ReadFile ( m_logger , casFile . data , readFileHandle , memoryBegin , toRead ) )
2023-11-29 18:47:11 -05:00
{
UBA_ASSERT ( false ) ; // Implement
2024-08-21 02:51:44 -04:00
return m_logger . Error ( TC ( " Failed to read file %s (%s) (2) " ) , casFile . data , LastErrorToText ( ) . data ) ; ;
2023-11-29 18:47:11 -05:00
}
memcpy ( writeBuffer , memoryPos , toWrite ) ;
memoryPos + = toWrite ;
2024-02-19 01:59:59 -05:00
CloseFile ( casFile . data , readFileHandle ) ;
readFileHandle = InvalidFileHandle ;
2023-11-29 18:47:11 -05:00
}
2024-07-22 18:34:54 -04:00
todoRemoveMe = 8 ;
2023-11-29 18:47:11 -05:00
u64 actualSize = fileSize ;
if ( m_storeCompressed )
actualSize = * ( u64 * ) writeBuffer ;
StorageStats & stats = Stats ( ) ;
stats . sendCasBytesComp + = fileSize ;
stats . sendCasBytesRaw + = actualSize ;
left - = toWrite ;
if ( ! left )
{
* fetchId = u16 ( ~ 0 ) ;
u64 sendCasTime = GetTime ( ) - start ;
2024-06-02 18:14:50 -04:00
stats . sendCas + = Timer { sendCasTime , 1 } ;
2023-11-29 18:47:11 -05:00
return true ;
}
2024-07-22 18:34:54 -04:00
todoRemoveMe = 9 ;
2023-11-29 18:47:11 -05:00
mvg . Cancel ( ) ;
cg . Cancel ( ) ;
2023-12-12 21:25:58 -05:00
rfg . Cancel ( ) ;
2023-11-29 18:47:11 -05:00
* fetchId = PopId ( ) ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_activeFetchesLock , lock ) ;
2023-11-29 18:47:11 -05:00
auto insres = m_activeFetches . try_emplace ( * fetchId ) ;
UBA_ASSERT ( insres . second ) ;
2024-03-08 18:31:48 -05:00
ActiveFetch & fetch = insres . first - > second ;
fetch . clientId = connectionInfo . GetId ( ) ;
2024-02-19 01:59:59 -05:00
lock . Leave ( ) ;
2024-07-22 18:34:54 -04:00
todoRemoveMe = 10 ;
2024-02-19 01:59:59 -05:00
mappedView . size = fileSize ;
2023-11-29 18:47:11 -05:00
fetch . readFileHandle = readFileHandle ;
fetch . mappedView = mappedView ;
2024-02-19 01:59:59 -05:00
fetch . ownsMapping = ownsMapping ;
2023-11-29 18:47:11 -05:00
fetch . memoryBegin = memoryBegin ;
fetch . memoryPos = memoryPos ;
fetch . left = left ;
fetch . casKey = casKey ;
fetch . sendCasTime = GetTime ( ) - start ;
2024-02-19 01:59:59 -05:00
2023-11-29 18:47:11 -05:00
return true ;
}
case StorageMessageType_FetchSegment :
{
u64 start = GetTime ( ) ;
u16 fetchId = reader . ReadU16 ( ) ;
u32 fetchIndex = reader . ReadU32 ( ) ;
2024-02-26 01:14:42 -05:00
SCOPED_READ_LOCK ( m_activeFetchesLock , lock ) ;
2023-11-29 18:47:11 -05:00
auto findIt = m_activeFetches . find ( fetchId ) ;
if ( findIt = = m_activeFetches . end ( ) )
2024-07-24 18:51:02 -04:00
return m_logger . Error ( TC ( " Can't find active fetch %u, disconnected client? (fetch index %u, client id %u uid %s) " ) , fetchId , fetchIndex , connectionInfo . GetId ( ) , GuidToString ( connectionInfo . GetUid ( ) ) . str ) ;
2023-11-29 18:47:11 -05:00
ActiveFetch & fetch = findIt - > second ;
2024-03-08 18:31:48 -05:00
UBA_ASSERT ( fetch . clientId = = connectionInfo . GetId ( ) ) ;
2023-11-29 18:47:11 -05:00
lock . Leave ( ) ;
2024-02-19 01:59:59 -05:00
UBA_ASSERT ( fetchIndex ) ;
const u8 * pos = fetch . memoryPos + ( fetchIndex - 1 ) * writer . GetCapacityLeft ( ) ;
u64 toWrite = writer . GetCapacityLeft ( ) ;
if ( ( pos - fetch . memoryBegin ) + toWrite > fetch . mappedView . size )
toWrite = fetch . mappedView . size - ( pos - fetch . memoryBegin ) ;
2023-12-12 21:25:58 -05:00
2024-02-19 01:59:59 -05:00
memcpy ( writer . AllocWrite ( toWrite ) , pos , toWrite ) ;
2023-11-29 18:47:11 -05:00
2024-02-19 01:59:59 -05:00
bool isDone = fetch . left . fetch_sub ( toWrite ) = = toWrite ;
2023-11-29 18:47:11 -05:00
if ( ! isDone )
{
fetch . sendCasTime + = GetTime ( ) - start ;
return true ;
}
2024-02-19 01:59:59 -05:00
fetch . Release ( * this , TC ( " FetchDone " ) ) ;
2023-11-29 18:47:11 -05:00
u64 sendCasTime = fetch . sendCasTime ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_activeFetchesLock , activeLock ) ;
2023-11-29 18:47:11 -05:00
m_activeFetches . erase ( fetchId ) ;
activeLock . Leave ( ) ;
PushId ( fetchId ) ;
sendCasTime + = GetTime ( ) - start ;
2024-06-02 18:14:50 -04:00
Stats ( ) . sendCas + = Timer { sendCasTime , 1 } ;
2023-11-29 18:47:11 -05:00
return true ;
}
case StorageMessageType_FetchEnd :
{
CasKey key = reader . ReadCasKey ( ) ;
if ( m_traceFetch )
m_trace - > FileEndFetch ( connectionInfo . GetId ( ) , AsCompressed ( key , m_storeCompressed ) ) ;
return true ;
}
case StorageMessageType_ExistsOnServer :
{
CasKey casKey = reader . ReadCasKey ( ) ;
UBA_ASSERT ( IsCompressed ( casKey ) ) ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_casLookupLock , lookupLock ) ;
2023-11-29 18:47:11 -05:00
auto casInsres = m_casLookup . try_emplace ( casKey ) ;
CasEntry & casEntry = casInsres . first - > second ;
lookupLock . Leave ( ) ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( casEntry . lock , entryLock ) ;
2023-11-29 18:47:11 -05:00
2024-07-30 13:47:15 -04:00
if ( ! WaitForWritten ( casEntry , entryLock , connectionInfo , TC ( " UNKNOWN " ) ) )
2023-11-29 18:47:11 -05:00
return false ;
bool exists = casEntry . verified & & casEntry . exists ;
if ( ! exists & & casEntry . exists )
{
# if !UBA_USE_SPARSEFILE
StringBuffer < > casFile ;
if ( ! GetCasFileName ( casFile , casKey ) )
return false ;
u64 outFileSize = 0 ;
if ( FileExists ( m_logger , casFile . data , & outFileSize ) )
{
if ( outFileSize = = 0 & & casKey ! = EmptyFileKey )
{
m_logger . Warning ( TC ( " Found file %s with size 0 which did not have the zero-size-caskey. Deleting " ) , casFile . data ) ;
if ( ! uba : : DeleteFileW ( casFile . data ) )
return m_logger . Error ( TC ( " Failed to delete %s. Clean cas folder and restart " ) , casFile . data ) ;
casEntry . exists = false ;
2024-07-30 13:47:15 -04:00
casEntry . verified = true ;
2023-11-29 18:47:11 -05:00
}
else
{
casEntry . verified = true ;
exists = true ;
entryLock . Leave ( ) ;
CasEntryWritten ( casEntry , outFileSize ) ;
}
}
else
{
casEntry . exists = false ;
2024-07-30 13:47:15 -04:00
casEntry . verified = true ;
2023-11-29 18:47:11 -05:00
}
# endif
}
writer . WriteBool ( exists ) ;
return true ;
}
case StorageMessageType_StoreBegin :
{
u64 start = GetTime ( ) ;
CasKey casKey = reader . ReadCasKey ( ) ;
u64 fileSize = reader . ReadU64 ( ) ;
u64 actualSize = reader . ReadU64 ( ) ;
UBA_ASSERT ( IsCompressed ( casKey ) ) ;
StringBuffer < > hint ;
reader . ReadString ( hint ) ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_casLookupLock , lookupLock ) ;
2023-11-29 18:47:11 -05:00
auto casInsres = m_casLookup . try_emplace ( casKey ) ;
CasEntry & casEntry = casInsres . first - > second ;
lookupLock . Leave ( ) ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( casEntry . lock , entryLock ) ;
2023-11-29 18:47:11 -05:00
if ( ! casEntry . verified )
{
casEntry . key = casKey ;
casEntry . verified = true ;
}
else
{
2024-07-30 13:47:15 -04:00
if ( ! WaitForWritten ( casEntry , entryLock , connectionInfo , hint . data ) )
2023-11-29 18:47:11 -05:00
return false ;
if ( casEntry . exists )
{
entryLock . Leave ( ) ;
CasEntryAccessed ( casEntry ) ;
writer . WriteU16 ( u16 ( ~ 0 ) ) ;
2024-05-08 12:53:11 -04:00
writer . WriteBool ( m_traceStore ) ;
2023-11-29 18:47:11 -05:00
return true ;
}
}
if ( ! fileSize )
{
m_logger . Error ( TC ( " Store from client is of 0 size (%s) " ) , hint . data ) ;
casEntry . verified = false ;
return false ;
}
2024-04-05 19:10:53 -04:00
MappedView mappedView ;
FileAccessor * fileAccessor = nullptr ;
if ( m_writeRecievedCasFilesToDisk )
2023-11-29 18:47:11 -05:00
{
2024-04-05 19:10:53 -04:00
StringBuffer < > casKeyName ;
GetCasFileName ( casKeyName , casKey ) ;
2024-05-28 15:07:55 -04:00
const tchar * filename = TStrdup ( casKeyName . data ) ;
fileAccessor = new FileAccessor ( m_logger , filename ) ;
2024-04-05 19:10:53 -04:00
if ( ! fileAccessor - > CreateMemoryWrite ( false , DefaultAttributes ( ) , fileSize , m_tempPath . data ) )
{
delete fileAccessor ;
2024-04-24 20:07:13 -04:00
free ( ( void * ) filename ) ;
2024-04-05 19:10:53 -04:00
m_logger . Error ( TC ( " Failed to create cas file %s " ) , casKeyName . data ) ;
casEntry . verified = false ;
return false ;
}
2024-05-28 15:07:55 -04:00
# ifdef __clang_analyzer__ // Seems clang analyzer gets lost
free ( ( void * ) filename ) ;
# endif
2024-04-05 19:10:53 -04:00
mappedView . memory = fileAccessor - > GetData ( ) ;
}
else
{
mappedView = m_casDataBuffer . AllocAndMapView ( MappedView_Transient , fileSize , 1 , CasKeyString ( casKey ) . str ) ;
if ( ! mappedView . memory )
{
casEntry . verified = false ;
return false ;
}
2023-11-29 18:47:11 -05:00
}
casEntry . beingWritten = true ;
firstStore = & tempStore ;
* ( u64 * ) mappedView . memory = fileSize ;
firstStore - > casEntry = & casEntry ;
firstStore - > fileSize = fileSize ;
firstStore - > actualSize = actualSize ;
firstStore - > mappedView = mappedView ;
2024-04-05 19:10:53 -04:00
firstStore - > fileAccessor = fileAccessor ;
2023-11-29 18:47:11 -05:00
firstStore - > recvCasTime = GetTime ( ) - start ;
if ( m_trace )
m_trace - > FileBeginStore ( connectionInfo . GetId ( ) , casKey , fileSize , hint . data , m_traceStore ) ;
[[fallthrough]] ;
}
case StorageMessageType_StoreSegment :
{
u64 start = GetTime ( ) ;
u16 storeId = 0 ;
u64 memOffset = 0 ;
ActiveStore * activeStoreTemp = firstStore ;
if ( ! firstStore ) // If this is set we are a continuation from StorageMessageType_Begin
{
storeId = reader . ReadU16 ( ) ;
memOffset = reader . ReadU64 ( ) ;
2024-02-26 01:14:42 -05:00
SCOPED_READ_LOCK ( m_activeStoresLock , activeLock ) ;
2023-11-29 18:47:11 -05:00
auto storeIt = m_activeStores . find ( storeId ) ;
if ( storeIt = = m_activeStores . end ( ) )
return m_logger . Error ( TC ( " Can't find active store %u, disconnected client? " ) , storeId ) ;
activeStoreTemp = & storeIt - > second ;
2024-03-08 18:31:48 -05:00
UBA_ASSERT ( activeStoreTemp - > clientId = = connectionInfo . GetId ( ) ) ;
2023-11-29 18:47:11 -05:00
}
ActiveStore & activeStore = * activeStoreTemp ;
u64 toRead = reader . GetLeft ( ) ;
reader . ReadBytes ( activeStore . mappedView . memory + memOffset , toRead ) ;
2024-02-19 18:41:16 -05:00
u64 time2 = GetTime ( ) ;
activeStore . recvCasTime + = time2 - start ;
2024-02-21 01:43:26 -05:00
u64 fileSize = activeStore . fileSize ;
2023-11-29 18:47:11 -05:00
u64 totalWritten = activeStore . totalWritten . fetch_add ( toRead ) + toRead ;
2024-02-21 01:43:26 -05:00
if ( totalWritten = = fileSize )
2023-11-29 18:47:11 -05:00
{
m_casDataBuffer . UnmapView ( activeStore . mappedView , TC ( " StoreDone " ) ) ;
2024-04-05 19:10:53 -04:00
if ( activeStore . fileAccessor )
{
bool success = activeStore . fileAccessor - > Close ( ) ;
2024-04-24 20:07:13 -04:00
const tchar * filename = activeStore . fileAccessor - > GetFileName ( ) ;
2024-04-05 19:10:53 -04:00
delete activeStore . fileAccessor ;
2024-04-24 20:07:13 -04:00
free ( ( void * ) filename ) ;
2024-04-05 19:10:53 -04:00
if ( ! success )
return m_logger . Error ( TC ( " REVISIT THIS! " ) ) ;
}
2023-11-29 18:47:11 -05:00
CasEntry & casEntry = * activeStore . casEntry ;
{
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( casEntry . lock , entryLock ) ;
2023-11-29 18:47:11 -05:00
casEntry . mappingHandle = activeStore . mappedView . handle ;
casEntry . mappingOffset = activeStore . mappedView . offset ;
casEntry . mappingSize = totalWritten ;
casEntry . exists = true ;
casEntry . beingWritten = false ;
}
2024-04-12 19:42:04 -04:00
bool isPersistentStore = m_writeRecievedCasFilesToDisk ;
2023-11-29 18:47:11 -05:00
if ( isPersistentStore )
CasEntryWritten ( * activeStore . casEntry , totalWritten ) ;
2024-02-19 18:41:16 -05:00
activeStore . recvCasTime + = GetTime ( ) - time2 ;
2023-11-29 18:47:11 -05:00
StorageStats & stats = Stats ( ) ;
2024-06-02 18:14:50 -04:00
stats . recvCas + = Timer { activeStore . recvCasTime , 1 } ;
2023-11-29 18:47:11 -05:00
stats . recvCasBytesComp + = activeStore . fileSize ;
stats . recvCasBytesRaw + = activeStore . actualSize ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_waitEntriesLock , waitLock ) ;
2023-11-29 18:47:11 -05:00
auto waitFindIt = m_waitEntries . find ( casEntry . key ) ;
if ( waitFindIt ! = m_waitEntries . end ( ) )
{
WaitEntry & waitEntry = waitFindIt - > second ;
waitEntry . Success = true ;
2024-07-24 02:26:22 -04:00
waitEntry . done . Set ( ) ;
2023-11-29 18:47:11 -05:00
}
waitLock . Leave ( ) ;
if ( ! firstStore )
{
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_activeStoresLock , activeLock ) ;
2023-11-29 18:47:11 -05:00
m_activeStores . erase ( storeId ) ;
activeLock . Leave ( ) ;
PushId ( storeId ) ;
}
else
{
writer . WriteU16 ( 0 ) ;
writer . WriteBool ( m_traceStore ) ;
}
return true ;
}
if ( firstStore )
{
storeId = PopId ( ) ;
UBA_ASSERT ( storeId ! = 0 ) ;
writer . WriteU16 ( storeId ) ;
writer . WriteBool ( m_traceStore ) ;
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_activeStoresLock , activeLock ) ;
2023-11-29 18:47:11 -05:00
auto insres = m_activeStores . try_emplace ( storeId ) ;
UBA_ASSERT ( insres . second ) ;
2024-03-08 18:31:48 -05:00
ActiveStore & s = insres . first - > second ;
s . clientId = connectionInfo . GetId ( ) ;
2023-11-29 18:47:11 -05:00
activeLock . Leave ( ) ;
s . fileSize = firstStore - > fileSize ;
s . mappedView = firstStore - > mappedView ;
2024-04-05 19:10:53 -04:00
s . fileAccessor = firstStore - > fileAccessor ;
2023-11-29 18:47:11 -05:00
s . casEntry = firstStore - > casEntry ;
s . totalWritten = firstStore - > totalWritten . load ( ) ;
s . recvCasTime = firstStore - > recvCasTime . load ( ) ;
}
return true ;
}
case StorageMessageType_StoreEnd :
{
CasKey key = reader . ReadCasKey ( ) ;
if ( m_traceStore )
m_trace - > FileEndStore ( connectionInfo . GetId ( ) , key ) ;
return true ;
}
}
UBA_ASSERT ( false ) ;
return false ;
}
u16 StorageServer : : PopId ( )
{
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_availableIdsLock , lock ) ;
2023-11-29 18:47:11 -05:00
if ( m_availableIds . empty ( ) )
{
UBA_ASSERT ( m_availableIdsHigh < u16 ( ~ 0 ) - 1 ) ;
return m_availableIdsHigh + + ;
}
u16 storeId = m_availableIds . back ( ) ;
m_availableIds . pop_back ( ) ;
return storeId ;
}
void StorageServer : : PushId ( u16 id )
{
2024-02-26 01:14:42 -05:00
SCOPED_WRITE_LOCK ( m_availableIdsLock , lock ) ;
2023-11-29 18:47:11 -05:00
m_availableIds . push_back ( id ) ;
}
}