1% Layered Queueing Network (LQN) - Production 4-Tier J2EE Architecture Model
3% This example demonstrates a comprehensive 4-layer J2EE system architecture:
6% - Reference task with 1 user (closed
class)
7% - Represents browser clients with sequential user operations
9% Layer 2: APPLICATION LAYER
10% - Service task handling 4 concurrent web requests
11% - Multiple entries (renderHomePage, processProductPage, handleLogin, checkoutWorkflow)
12% - Complex activity precedence with or-fork/or-join branching
14% Layer 3: DATABASE LAYER
15% - Service task managing database operations
16% - Multiple entries
for different query types (read, write, query, log)
17% - Sequential activity chains
19% The model demonstrates:
20% - Multiple entries per task
21% - Complex activity precedence patterns (serial, or-fork, or-join)
22% - Synchronous call routing between layers
23% - Load-dependent processing characteristics
24% - Production-grade LQN features
26% This
is a reference model
for validating SolverLN against complex layered systems.
27% For cache support variant, see: example_layered_production_4tier_cache.m
32model = LayeredNetwork(
'testLQN3');
34%% Layer 1: CLIENT LAYER
35P0 = Processor(model,
'P0', 1, SchedStrategy.PS);
36T0 = Task(model,
'T0', 1, SchedStrategy.REF).on(P0); % Reference task with 1 user
37E0 = Entry(model,
'E0').on(T0); % Single entry point
for all client requests
39%% Layer 2: APPLICATION SERVER LAYER
40P1 = Processor(model,
'P1', 1, SchedStrategy.PS);
41T1 = Task(model,
'T1', 1, SchedStrategy.FCFS).on(P1); % FCFS
for serialization
42E10 = Entry(model,
'E10').on(T1); % renderHomePage
43E11 = Entry(model,
'E11').on(T1); % processProductPage
44E12 = Entry(model,
'E12').on(T1); % handleLogin
45E13 = Entry(model,
'E13').on(T1); % checkoutWorkflow
47%% Layer 3: DATABASE LAYER
48P2 = Processor(model,
'P2', 1, SchedStrategy.PS);
49T2 = Task(model,
'T2', 1, SchedStrategy.FCFS).on(P2); % Database serialization
50E20 = Entry(model,
'E20').on(T2); % readUserProfile
51E21 = Entry(model,
'E21').on(T2); % getProductInfo
52E22 = Entry(model,
'E22').on(T2); % writeOrderData
53E23 = Entry(model,
'E23').on(T2); % logSessionEvent
55%% CLIENT LAYER ACTIVITIES
56% Sequential processing flow: login → browse → shop → checkout
57A0 = Activity(model,
'A0', Exp(1.0)).on(T0).boundTo(E0).synchCall(E12, 1.0); % login -> handleLogin
58A1 = Activity(model,
'A1', Exp(1.0)).on(T0).synchCall(E10, 1.0); % browseSession -> renderHomePage
59A2 = Activity(model,
'A2', Exp(1.0)).on(T0).synchCall(E11, 1.0); % viewProductPage -> processProductPage
60A3 = Activity(model,
'A3', Exp(1.0)).on(T0).synchCall(E13, 1.0); % submitCheckout -> checkoutWorkflow
62%% APPLICATION LAYER ACTIVITIES
63% Entry E10: renderHomePage
64B0 = Activity(model,
'B0', Exp(1.0)).on(T1).boundTo(E10); % renderStaticContent
65B1 = Activity(model,
'B1', Exp(1.0)).on(T1).repliesTo(E10); % fetchRecommendations
67% Entry E11: processProductPage
68B2 = Activity(model,
'B2', Exp(1.0)).on(T1).boundTo(E11); % parseRequest
69B3 = Activity(model,
'B3', Exp(1.0)).on(T1).synchCall(E21, 1.0).repliesTo(E11); % getProductDetails -> getProductInfo
71% Entry E12: handleLogin
72B4 = Activity(model,
'B4', Exp(1.0)).on(T1).boundTo(E12).synchCall(E20, 1.0).repliesTo(E12); % validateCredentials -> readUserProfile
74% Entry E13: checkoutWorkflow
75B5 = Activity(model,
'B5', Exp(1.0)).on(T1).boundTo(E13); % verifyCart
76B6 = Activity(model,
'B6', Exp(1.0)).on(T1); % computeTotalPrice
77B7 = Activity(model,
'B7', Exp(1.0)).on(T1).synchCall(E22, 1.0); % WriteOrder
78B7a = Activity(model,
'B7a', Exp(1.0)).on(T1); % skipLog (30% probability)
79B7b = Activity(model,
'B7b', Exp(1.0)).on(T1).synchCall(E23, 1.0); % logOrder (70% probability)
80B8 = Activity(model,
'B8', Exp(1.0)).on(T1).repliesTo(E13); % success
82%% DATABASE LAYER ACTIVITIES
83% Entry E20: readUserProfile
84C0 = Activity(model,
'C0', Exp(1.0)).on(T2).boundTo(E20); % parseReadQuery
85C1 = Activity(model,
'C1', Exp(1.0)).on(T2).repliesTo(E20); % fetchFromDisk
87% Entry E21: getProductInfo
88C2 = Activity(model,
'C2', Exp(1.0)).on(T2).boundTo(E21).repliesTo(E21); % readCache (in-DB cache)
90% Entry E22: writeOrderData
91C3 = Activity(model,
'C3', Exp(1.0)).on(T2).boundTo(E22); % parseWriteQuery
92C4 = Activity(model,
'C4', Exp(1.0)).on(T2); % writeToDisk
93C5 = Activity(model,
'C5', Exp(1.0)).on(T2).repliesTo(E22); % updateIndex
95% Entry E23: logSessionEvent
96C6 = Activity(model,
'C6', Exp(1.0)).on(T2).boundTo(E23).repliesTo(E23); % appendToLog
98%% ACTIVITY PRECEDENCES - CLIENT LAYER
99% Sequential flow through all client operations
100T0.addPrecedence(ActivityPrecedence.Serial(A0, A1, A2, A3));
102%% ACTIVITY PRECEDENCES - APPLICATION LAYER
103% Path 1: renderHomePage flow
104T1.addPrecedence(ActivityPrecedence.Serial(B0, B1));
106% Path 2: processProductPage flow
107T1.addPrecedence(ActivityPrecedence.Serial(B2, B3));
109% Path 3: checkoutWorkflow flow with branching
110T1.addPrecedence(ActivityPrecedence.Serial(B5, B6, B7)); % Sequential: verify -> compute -> write
111T1.addPrecedence(ActivityPrecedence.OrFork(B7, {B7a, B7b}, [0.7, 0.3])); % 70% skip, 30% log
112T1.addPrecedence(ActivityPrecedence.OrJoin({B7a, B7b}, B8)); % Converge branches to success
114%% ACTIVITY PRECEDENCES - DATABASE LAYER
115% Query path 1: readUserProfile
116T2.addPrecedence(ActivityPrecedence.Serial(C0, C1));
118% Query path 2: writeOrderData with index update
119T2.addPrecedence(ActivityPrecedence.Serial(C3, C4, C5));
121%% SOLVE WITH SOLVERMVA (Layer solver) inside SolverLN
122fprintf(
'\n=== Solving 4-Tier LQN with SolverLN + MVA ===\n');
123lnoptions = LN.defaultOptions;
124lnoptions.verbose = VerboseLevel.STD;
125mvaopt = MVA.defaultOptions;
126mvaopt.verbose = VerboseLevel.SILENT;
128solver = LN(model, @(layer) MVA(layer, mvaopt), lnoptions);
129AvgTable = solver.getAvgTable;
131fprintf(
'\n=== Results ===\n');
134%% Alternative: Solve with SolverFluid (approximation)
135% Uncomment to compare with fluid approximation
136% fprintf(
'\n=== Solving 4-Tier LQN with SolverLN + SolverFluid (Approximation) ===\n');
137% lnoptions = LN.defaultOptions;
138% lnoptions.verbose = VerboseLevel.STD;
139% fluidopt = SolverFluid.defaultOptions;
140% fluidopt.verbose = VerboseLevel.SILENT;
142% solver_fluid = LN(model, @(layer) SolverFluid(layer, fluidopt), lnoptions);
143% AvgTable_fluid = solver_fluid.getAvgTable;
144% disp(
'Fluid Approximation Results:');
145% disp(AvgTable_fluid);