Skip to content

Commit 2e743d5

Browse files
committed
Don't retry mod load on error, but allow a new load if DB is reloaded
1 parent 4860278 commit 2e743d5

File tree

5 files changed

+73
-23
lines changed

5 files changed

+73
-23
lines changed

MMManaged/MeshRelation.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,8 @@ module MeshRelation =
267267

268268
modVertRels
269269

270-
271270
let buildIt() =
271+
//log.Info "Starting build of meshrelation for mod: %A" md.Name
272272
modMesh <- Some ((verifyAndGet md.Name md.Mesh).Force())
273273
refMesh <- Some ((ref.Mesh.Force()))
274274

@@ -280,7 +280,7 @@ module MeshRelation =
280280

281281
let vertRels = lazy (buildIt())
282282

283-
member x.IsBuilt = vertRels.IsValueCreated
283+
member x.IsBuilt = vertRels.IsValueCreated
284284
member x.Build() = vertRels.Force()
285285

286286
member x.DBMod = md

MMManaged/ModDB.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ module ModDB =
647647
| None -> newMeshRel()
648648
| _ -> newMeshRel()
649649
)
650-
log().Info "MeshRelations: %d cached, %d built" nCached nBuilt
650+
log().Info "MeshRelations: %d cached, %d new" nCached nBuilt
651651
meshRels
652652

653653
// this code forces an immediate load of the data, maybe useful for debugging

MMManaged/ModDBInterop.fs

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,16 @@ module ModDBInterop =
311311
List.item delIdx moddb.DeletionMods
312312
| n -> failwithf "invalid mod index: %A" i
313313

314-
// technically, because I use an exclusive lock below, this doesn't need to be a concurrent dictionary
315-
let modLoadThread = new System.Collections.Concurrent.ConcurrentDictionary<string, System.Threading.Thread>()
314+
/// Used to track the loading thread for a mod (see lodModData for more details).
315+
type LoadInfo = {
316+
Thread: System.Threading.Thread
317+
/// When the database is reloaded this will change, allowing a new set of loads. This is useful
318+
/// if some of the mods had errors that have been corrected.
319+
MeshRelationId: int
320+
LastLoadHadError: option<bool>
321+
}
322+
323+
let modLoadThread = new System.Collections.Concurrent.ConcurrentDictionary<string, LoadInfo>()
316324

317325
/// Load the mod data for mod i. This is assumed to be an index into the mesh relation list.
318326
/// If the mesh relation is already built, this does nothing (the mod is not reloaded).
@@ -329,30 +337,56 @@ module ModDBInterop =
329337
/// to this function. The native code should observe that the (new) mesh relation's data is still
330338
/// unavailable and trigger a another call to this function on an ongoing basis until the old thread
331339
/// finishes and a new one can be started.
332-
let loadModData(i) =
340+
let loadModData(i) =
333341
let mutable loadState = 0 // not available
334-
try
342+
try
335343
let moddb = State.Data.Moddb
336-
if i < moddb.MeshRelations.Length then
344+
if i < moddb.MeshRelations.Length then
337345
let meshrel = List.item i (moddb.MeshRelations)
338-
339-
if meshrel.IsBuilt then
346+
347+
if meshrel.IsBuilt then
340348
loadState <- 1 // loaded
341-
else
349+
else
342350
let loadKey = i.ToString() + meshrel.DBMod.Name + meshrel.DBRef.Name
351+
let currentMeshRelId = meshrel.GetHashCode()
343352

344-
Locking.write( fun _ ->
345-
let ok,mlt = modLoadThread.TryGetValue loadKey
346-
if not ok || (ok && not mlt.IsAlive) then
347-
let loadit() =
353+
let loadit () =
354+
let ok,currInfo = modLoadThread.TryGetValue loadKey
355+
if ok then
356+
try
357+
//log.Info "beginning new load for key %A with meshrel id %A (curr load info: %A)" loadKey currentMeshRelId currInfo
348358
meshrel.Build() |> ignore
349-
let t = new System.Threading.Thread( new System.Threading.ThreadStart(loadit) )
350-
t.Start()
351-
modLoadThread.AddOrUpdate(loadKey, t, (fun _ (oldT) -> t)) |> ignore
352-
loadState <- 2 // load was started
353-
else
354-
loadState <- 3 // a started load is still pending
355-
)
359+
let newInfo = { currInfo with LastLoadHadError = Some(false) }
360+
modLoadThread.TryUpdate(loadKey, newInfo, currInfo) |> ignore
361+
with
362+
| e ->
363+
// this is in a separate thread so log explicitly to make sure it goes to output log
364+
log.Error "Mesh relation build exception: %A" e
365+
let newInfo = { currInfo with LastLoadHadError = Some(true) }
366+
modLoadThread.TryUpdate(loadKey, newInfo, currInfo) |> ignore
367+
else
368+
log.Error "load info for mod %A not found" meshrel.DBMod.Name
369+
370+
let startNewLoad() =
371+
let t = new System.Threading.Thread(new System.Threading.ThreadStart(loadit))
372+
let newLoadInfo = { Thread = t; MeshRelationId = currentMeshRelId; LastLoadHadError = None }
373+
modLoadThread.AddOrUpdate(loadKey, newLoadInfo, (fun _ _ -> newLoadInfo)) |> ignore
374+
t.Start()
375+
loadState <- 2 // load was started
376+
377+
Locking.write (fun _ ->
378+
match modLoadThread.TryGetValue(loadKey) with
379+
| (true, loadInfo) ->
380+
//log.Info "Found existing load entry: %A (curr meshrel is: %A)" loadInfo currentMeshRelId
381+
if loadInfo.MeshRelationId = currentMeshRelId && loadInfo.LastLoadHadError = Some true then
382+
loadState <- 4 // error encountered previously, do not start a new load
383+
elif loadInfo.Thread.IsAlive then
384+
loadState <- 3 // a started load is still pending
385+
else
386+
startNewLoad()
387+
| (false, _) ->
388+
startNewLoad()
389+
)
356390
loadState
357391
with
358392
| e ->

Native/mod_load/src/mod_load.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ unsafe fn load_tex(dp:DevicePointer, texpath:&[u16]) -> Option<TexPtr> {
118118
}
119119
}
120120

121+
const MAX_FILL_ATTEMPTS:u32 = 1;
121122
/// Create D3D resources for a mod using the data loaded by managed code. This usually consists of a
122123
/// vertex buffer, declaration and optionally one or more textures. `midx` is the mod index
123124
/// into the current mod DB (and should be less than GetModCount()).
@@ -554,6 +555,7 @@ pub unsafe fn setup_mod_data(device: DevicePointer, callbacks: interop::ManagedC
554555
parent_mod_names: parent_mods,
555556
last_frame_render: 0,
556557
name: mod_name.to_owned(),
558+
fill_attempts: 0,
557559
};
558560

559561
// get mod key
@@ -746,6 +748,14 @@ pub unsafe fn load_deferred_mods(device: DevicePointer, callbacks: interop::Mana
746748
let mut nmod =
747749
get_mod_by_name(&nmd, &mut GLOBAL_STATE.loaded_mods);
748750
if let Some(ref mut nmod) = nmod {
751+
if nmod.fill_attempts > MAX_FILL_ATTEMPTS {
752+
if nmod.fill_attempts == MAX_FILL_ATTEMPTS + 1 {
753+
write_log_file(&format!("load_deferred_mods warning: mod exceeded max fill attempts, no more will be done: {}", nmod.name));
754+
// increment so that we don't log about it again
755+
nmod.fill_attempts += 1;
756+
}
757+
continue;
758+
}
749759
if let ModD3DState::Loaded(_) = nmod.d3d_data {
750760
write_log_file(&format!("load_deferred_mods: mod already loaded: {}", nmod.name));
751761
continue;
@@ -754,15 +764,19 @@ pub unsafe fn load_deferred_mods(device: DevicePointer, callbacks: interop::Mana
754764
let mdat: *mut interop::ModData = (callbacks.GetModData)(nmod.midx);
755765
if mdat != null_mut() {
756766
let mut lres = 0;
757-
if !(*mdat).data_available {
767+
if !(*mdat).data_available {
758768
lres = (callbacks.LoadModData)(nmod.midx);
759769
match lres {
760770
0 => write_log_file(&format!("load_deferred_mods: mod data not yet available: {}", nmod.name)),
761771
1 => write_log_file(&format!("load_deferred_mods: mod data is now available: {}", nmod.name)),
762772
2 => write_log_file(&format!("load_deferred_mods: mod data load has started: {}", nmod.name)),
763773
3 => write_log_file(&format!("load_deferred_mods: mod data load is in progress: {}", nmod.name)),
774+
4 => write_log_file(&format!("load_deferred_mods: mod data load had error: {}", nmod.name)),
764775
n=> write_log_file(&format!("load_deferred_mods: unexpected return code: {} for mod: {}", n, nmod.name)),
765776
}
777+
if lres == 2 || lres == 4 {
778+
nmod.fill_attempts += 1;
779+
}
766780

767781
if lres != 1 {
768782
continue;

Native/types/src/native_mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub struct NativeModData {
4040
pub parent_mod_names: Vec<String>,
4141
pub last_frame_render: u64,
4242
pub name: String,
43+
pub fill_attempts: u32,
4344
}
4445

4546
pub const MAX_RECENT_RENDER_USAGE_THRESH:u64 = 500;
@@ -55,6 +56,7 @@ impl NativeModData {
5556
parent_mod_names: vec![],
5657
last_frame_render: 0,
5758
name: "".to_owned(),
59+
fill_attempts: 0,
5860
}
5961
}
6062
pub fn mod_key(vert_count: u32, prim_count: u32) -> u32 {

0 commit comments

Comments
 (0)