55
55
covering_index => 'maybe' (# idx {})
56
56
}.
57
57
58
+ -type mrargs_extra_item () ::
59
+ {callback , {atom (), atom ()}}
60
+ | {selector , any ()}
61
+ | {callback_args , viewcbargs ()}
62
+ | {ignore_partition_query_limit , boolean ()}
63
+ | {execution_stats_map , boolean ()}
64
+ | {execution_stats_rolling , boolean ()}.
65
+ -type mrargs_extra () :: [mrargs_extra_item ()].
66
+
58
67
-spec viewcbargs_new (Selector , Fields , CoveringIndex ) -> ViewCBArgs when
59
68
Selector :: selector (),
60
69
Fields :: fields (),
@@ -207,7 +216,9 @@ base_args(#cursor{index = Idx, selector = Selector, fields = Fields} = Cursor) -
207
216
% - Return execution statistics in a map
208
217
{execution_stats_map , true },
209
218
% - Return view rows in a map
210
- {view_row_map , true }
219
+ {view_row_map , true },
220
+ % - Stream execution statistics
221
+ {execution_stats_rolling , true }
211
222
]
212
223
}.
213
224
@@ -341,6 +352,43 @@ choose_best_index(IndexRanges) ->
341
352
{SelectedIndex , SelectedIndexRanges , _ } = hd (SortedIndexRanges ),
342
353
{{SelectedIndex , SelectedIndexRanges }, SortedIndexRanges }.
343
354
355
+ -spec format_stats (RawStats , Options ) -> FormattedStats when
356
+ RawStats :: shard_stats_v2 (),
357
+ Options :: mrargs_extra (),
358
+ FormattedStats :: shard_stats_v1 () | shard_stats_v2 ().
359
+ format_stats (Stats , Options ) when is_list (Options ) ->
360
+ case couch_util :get_value (execution_stats_map , Options , false ) of
361
+ true ->
362
+ Stats ;
363
+ false ->
364
+ #{docs_examined := DocsExamined } = Stats ,
365
+ {docs_examined , DocsExamined }
366
+ end .
367
+
368
+ -spec submit_stats (Options ) -> ok when
369
+ Options :: mrargs_extra ().
370
+ submit_stats (Options ) when is_list (Options ) ->
371
+ ShardStats = mango_execution_stats :shard_get_stats (),
372
+ Stats = format_stats (ShardStats , Options ),
373
+ % Send execution stats in batch (shard-level)
374
+ ok = rexi :stream2 ({execution_stats , Stats }).
375
+
376
+ -spec roll_stats (ViewRow , Options ) -> ViewRow when
377
+ ViewRow :: view_row (),
378
+ Options :: mrargs_extra ().
379
+ roll_stats (ViewRow , Options ) when is_list (Options ) ->
380
+ ViewRowMap = couch_util :get_value (view_row_map , Options , false ),
381
+ RollingStats = couch_util :get_value (execution_stats_rolling , Options , false ),
382
+ case ViewRowMap andalso RollingStats of
383
+ true ->
384
+ ShardStats = mango_execution_stats :shard_get_stats (),
385
+ mango_execution_stats :shard_init (),
386
+ Stats = format_stats (ShardStats , Options ),
387
+ fabric_view_row :set_stats (ViewRow , Stats );
388
+ false ->
389
+ ViewRow
390
+ end .
391
+
344
392
-spec view_cb
345
393
(Message , # mrargs {}) -> Response when
346
394
Message :: {meta , any ()} | {row , row_properties ()} | complete ,
@@ -382,7 +430,8 @@ view_cb({row, Props}, #mrargs{extra = Options} = Acc) ->
382
430
case match_and_extract_doc (Doc , Selector , Fields ) of
383
431
{match , FinalDoc } ->
384
432
ViewRow1 = fabric_view_row :set_doc (ViewRow , FinalDoc ),
385
- ok = rexi :stream2 (ViewRow1 ),
433
+ ViewRow2 = roll_stats (ViewRow1 , Options ),
434
+ ok = rexi :stream2 (ViewRow2 ),
386
435
set_mango_msg_timestamp ();
387
436
{no_match , undefined } ->
388
437
maybe_send_mango_ping ()
@@ -397,7 +446,8 @@ view_cb({row, Props}, #mrargs{extra = Options} = Acc) ->
397
446
Process (Doc );
398
447
{undefined , _ } ->
399
448
% include_docs=false. Use quorum fetch at coordinator
400
- ok = rexi :stream2 (ViewRow ),
449
+ ViewRow1 = roll_stats (ViewRow , Options ),
450
+ ok = rexi :stream2 (ViewRow1 ),
401
451
set_mango_msg_timestamp ();
402
452
{Doc , _ } ->
403
453
mango_execution_stats :shard_incr_docs_examined (),
@@ -406,17 +456,7 @@ view_cb({row, Props}, #mrargs{extra = Options} = Acc) ->
406
456
end ,
407
457
{ok , Acc };
408
458
view_cb (complete , # mrargs {extra = Options } = Acc ) ->
409
- ShardStats = mango_execution_stats :shard_get_stats (),
410
- Stats =
411
- case couch_util :get_value (execution_stats_map , Options , false ) of
412
- true ->
413
- ShardStats ;
414
- false ->
415
- DocsExamined = maps :get (docs_examined , ShardStats ),
416
- {docs_examined , DocsExamined }
417
- end ,
418
- % Send shard-level execution stats
419
- ok = rexi :stream2 ({execution_stats , Stats }),
459
+ submit_stats (Options ),
420
460
% Finish view output
421
461
ok = rexi :stream_last (complete ),
422
462
{ok , Acc };
@@ -472,6 +512,21 @@ maybe_send_mango_ping() ->
472
512
set_mango_msg_timestamp () ->
473
513
put (mango_last_msg_timestamp , os :timestamp ()).
474
514
515
+ -spec add_shard_stats (# execution_stats {}, shard_stats ()) -> # execution_stats {}.
516
+ add_shard_stats (Stats0 , {docs_examined , DocsExamined }) ->
517
+ mango_execution_stats :incr_docs_examined (Stats0 , DocsExamined );
518
+ add_shard_stats (Stats0 , #{} = ShardStats ) ->
519
+ DocsExamined = shard_stats_get (docs_examined , ShardStats ),
520
+ KeysExamined = shard_stats_get (keys_examined , ShardStats ),
521
+ Stats = mango_execution_stats :incr_docs_examined (Stats0 , DocsExamined ),
522
+ mango_execution_stats :incr_keys_examined (Stats , KeysExamined ).
523
+
524
+ -spec handle_execution_stats (# cursor {}, shard_stats ()) -> {ok , # cursor {}}.
525
+ handle_execution_stats (Cursor0 , ShardStats ) ->
526
+ # cursor {execution_stats = Stats } = Cursor0 ,
527
+ Cursor = Cursor0 # cursor {execution_stats = add_shard_stats (Stats , ShardStats )},
528
+ {ok , Cursor }.
529
+
475
530
-spec handle_message (message (), # cursor {}) -> Response when
476
531
Response ::
477
532
{ok , # cursor {}}
@@ -495,20 +550,10 @@ handle_message({row, Props}, Cursor) ->
495
550
couch_log :error (" ~s :: Error loading doc: ~p " , [? MODULE , Error ]),
496
551
{ok , Cursor }
497
552
end ;
498
- handle_message ({execution_stats , {docs_examined , DocsExamined }}, Cursor0 ) ->
499
- # cursor {execution_stats = Stats } = Cursor0 ,
500
- Cursor = Cursor0 # cursor {
501
- execution_stats = mango_execution_stats :incr_docs_examined (Stats , DocsExamined )
502
- },
503
- {ok , Cursor };
553
+ handle_message ({execution_stats , {docs_examined , _ } = ShardStats }, Cursor0 ) ->
554
+ handle_execution_stats (Cursor0 , ShardStats );
504
555
handle_message ({execution_stats , #{} = ShardStats }, Cursor0 ) ->
505
- DocsExamined = shard_stats_get (docs_examined , ShardStats ),
506
- KeysExamined = shard_stats_get (keys_examined , ShardStats ),
507
- # cursor {execution_stats = Stats0 } = Cursor0 ,
508
- Stats1 = mango_execution_stats :incr_docs_examined (Stats0 , DocsExamined ),
509
- Stats = mango_execution_stats :incr_keys_examined (Stats1 , KeysExamined ),
510
- Cursor = Cursor0 # cursor {execution_stats = Stats },
511
- {ok , Cursor };
556
+ handle_execution_stats (Cursor0 , ShardStats );
512
557
handle_message (complete , Cursor ) ->
513
558
{ok , Cursor };
514
559
handle_message ({error , Reason }, _Cursor ) ->
@@ -648,9 +693,14 @@ consider_index_coverage(Index, Fields, #mrargs{include_docs = IncludeDocs0} = Ar
648
693
| {no_match , null , {execution_stats , shard_stats ()}}
649
694
| any ().
650
695
doc_member_and_extract (Cursor , RowProps ) ->
651
- Db = Cursor # cursor .db ,
652
- Opts = Cursor # cursor .opts ,
653
- ExecutionStats = Cursor # cursor .execution_stats ,
696
+ # cursor {db = Db , opts = Opts , execution_stats = ExecutionStats0 } = Cursor ,
697
+ ExecutionStats =
698
+ case couch_util :get_value (stats , RowProps ) of
699
+ undefined ->
700
+ ExecutionStats0 ;
701
+ ShardStats ->
702
+ add_shard_stats (ExecutionStats0 , ShardStats )
703
+ end ,
654
704
Selector = Cursor # cursor .selector ,
655
705
case couch_util :get_value (doc , RowProps ) of
656
706
{DocProps } ->
@@ -748,7 +798,8 @@ base_opts_test() ->
748
798
}},
749
799
{ignore_partition_query_limit , true },
750
800
{execution_stats_map , true },
751
- {view_row_map , true }
801
+ {view_row_map , true },
802
+ {execution_stats_rolling , true }
752
803
],
753
804
MRArgs =
754
805
# mrargs {
@@ -1093,7 +1144,8 @@ t_execute_ok_all_docs(_) ->
1093
1144
}},
1094
1145
{ignore_partition_query_limit , true },
1095
1146
{execution_stats_map , true },
1096
- {view_row_map , true }
1147
+ {view_row_map , true },
1148
+ {execution_stats_rolling , true }
1097
1149
],
1098
1150
Args =
1099
1151
# mrargs {
@@ -1180,7 +1232,8 @@ t_execute_ok_query_view(_) ->
1180
1232
}},
1181
1233
{ignore_partition_query_limit , true },
1182
1234
{execution_stats_map , true },
1183
- {view_row_map , true }
1235
+ {view_row_map , true },
1236
+ {execution_stats_rolling , true }
1184
1237
],
1185
1238
Args =
1186
1239
# mrargs {
@@ -1279,7 +1332,8 @@ t_execute_ok_all_docs_with_execution_stats(_) ->
1279
1332
}},
1280
1333
{ignore_partition_query_limit , true },
1281
1334
{execution_stats_map , true },
1282
- {view_row_map , true }
1335
+ {view_row_map , true },
1336
+ {execution_stats_rolling , true }
1283
1337
],
1284
1338
Args =
1285
1339
# mrargs {
@@ -1394,6 +1448,8 @@ t_view_cb_row_matching_regular_doc(_) ->
1394
1448
fields => all_fields ,
1395
1449
covering_index => undefined
1396
1450
}},
1451
+ {execution_stats_map , true },
1452
+ {execution_stats_rolling , true },
1397
1453
{view_row_map , true }
1398
1454
]
1399
1455
},
@@ -1413,6 +1469,8 @@ t_view_cb_row_non_matching_regular_doc(_) ->
1413
1469
fields => all_fields ,
1414
1470
covering_index => undefined
1415
1471
}},
1472
+ {execution_stats_map , true },
1473
+ {execution_stats_rolling , true },
1416
1474
{view_row_map , true }
1417
1475
]
1418
1476
},
@@ -1432,6 +1490,8 @@ t_view_cb_row_null_doc(_) ->
1432
1490
fields => all_fields ,
1433
1491
covering_index => undefined
1434
1492
}},
1493
+ {execution_stats_map , true },
1494
+ {execution_stats_rolling , true },
1435
1495
{view_row_map , true }
1436
1496
]
1437
1497
},
@@ -1452,6 +1512,8 @@ t_view_cb_row_missing_doc_triggers_quorum_fetch(_) ->
1452
1512
fields => all_fields ,
1453
1513
covering_index => undefined
1454
1514
}},
1515
+ {execution_stats_map , true },
1516
+ {execution_stats_rolling , true },
1455
1517
{view_row_map , true }
1456
1518
]
1457
1519
},
@@ -1479,6 +1541,8 @@ t_view_cb_row_matching_covered_doc(_) ->
1479
1541
fields => Fields ,
1480
1542
covering_index => Index
1481
1543
}},
1544
+ {execution_stats_map , true },
1545
+ {execution_stats_rolling , true },
1482
1546
{view_row_map , true }
1483
1547
]
1484
1548
},
@@ -1503,6 +1567,8 @@ t_view_cb_row_non_matching_covered_doc(_) ->
1503
1567
fields => Fields ,
1504
1568
covering_index => Index
1505
1569
}},
1570
+ {execution_stats_map , true },
1571
+ {execution_stats_rolling , true },
1506
1572
{view_row_map , true }
1507
1573
]
1508
1574
},
@@ -1638,10 +1704,13 @@ t_handle_message_row_ok_above_limit(_) ->
1638
1704
user_acc = accumulator ,
1639
1705
user_fun = fun foo :bar /2
1640
1706
},
1641
- Row = [{id , id }, {key , key }, {doc , Doc }],
1707
+ ShardStats = #{keys_examined => 2 , docs_examined => 3 },
1708
+ Row = [{id , id }, {key , key }, {doc , Doc }, {stats , ShardStats }],
1642
1709
Cursor1 =
1643
1710
Cursor # cursor {
1644
- execution_stats = # execution_stats {resultsReturned = 1 },
1711
+ execution_stats = # execution_stats {
1712
+ resultsReturned = 1 , totalKeysExamined = 2 , totalDocsExamined = 3
1713
+ },
1645
1714
limit = 8 ,
1646
1715
user_acc = updated_accumulator ,
1647
1716
bookmark_docid = id ,
@@ -1689,12 +1758,15 @@ t_handle_message_row_ok_triggers_quorum_fetch_match(_) ->
1689
1758
user_acc = accumulator ,
1690
1759
limit = 1
1691
1760
},
1692
- Row = [{id , id }, {doc , undefined }],
1761
+ ShardStats = #{keys_examined => 2 , docs_examined => 3 },
1762
+ Row = [{id , id }, {doc , undefined }, {stats , ShardStats }],
1693
1763
Cursor1 =
1694
1764
Cursor # cursor {
1695
1765
execution_stats =
1696
1766
# execution_stats {
1697
1767
totalQuorumDocsExamined = 1 ,
1768
+ totalKeysExamined = 2 ,
1769
+ totalDocsExamined = 3 ,
1698
1770
resultsReturned = 1
1699
1771
},
1700
1772
user_acc = updated_accumulator ,
0 commit comments