private void MarkAsCalculating(ExcelReference caller, AsyncCallInfo asyncCallInfo) { calculatingRefs_[caller] = asyncCallInfo; for (int row = caller.RowFirst; row <= caller.RowLast; row++) { for (int col = caller.ColumnFirst; col <= caller.ColumnLast; col++) { ExcelReference excelReference = new ExcelReference(row, row, col, col, caller.SheetId); calculatingRefs_[excelReference] = asyncCallInfo; } } }
/// <summary> /// Starts async UDF calculation. /// Returns Scheduled/Calculating or calculated value. /// Make sure calling UDF marked with IsMacroType=true. /// </summary> public object Calc(CallArguments args) { CheckFuncName(args); MarkUdfNonVolatile(); ExcelReference caller; try { caller = GetCallerExcelReference(); } catch (Exception e) { logService_.WriteError( "Error getting reference. " + FunctionLoggerHelper.LogParameters(args.FunctionName, null), e); // TODO Cleanup return("Error getting reference."); } if (IsNewEvaluationBatchStarted) { OnEvaluatingBatchStarted(); } object[] asyncKeyArgs = GetAsyncKeyArgs(args.RawArgs, caller, batchStarted_); AsyncCallInfo asyncCallInfo = new AsyncCallInfo(args.FunctionName, asyncKeyArgs); if (!IsCalculatingTheSame(caller, asyncCallInfo) || IsScheduled(caller)) { // Check simple case. Precedent is still calculating. Precedents precedents = caller.GetPrecedents(); if (precedents.GetRefs().Any(IsCalculatingAny)) { SetEvalState(caller, EvalState.Scheduled, args, asyncCallInfo); return(Scheduled); } if (ForcePrecedentCalculated(caller, precedents)) { SetEvalState(caller, EvalState.Scheduled, args, asyncCallInfo); return(Scheduled); } } Validate(args); bool isCalculating; object result = Observe(asyncKeyArgs, caller.XlfToReference(), args, out isCalculating); if (isCalculating) { // Async call to service scheduled. SetEvalState(caller, EvalState.ObservableCreated, args, asyncCallInfo); return(Calculating); } else { // Async call to service and result are ready. SetEvalState(caller, EvalState.ObservableFinished, args, asyncCallInfo); return(result); } }
private void SetEvalState(ExcelReference caller, EvalState evalState, CallArguments args, AsyncCallInfo asyncCallInfo) { evalStates_[caller] = evalState; switch (evalState) { case EvalState.ObservableCreated: case EvalState.Scheduled: case EvalState.ForcingFormulaUpdate: MarkAsCalculating(caller, asyncCallInfo); LogState(); break; case EvalState.ObservableFinished: RemoveFromCalculating(caller); AddCalculatedFunc(caller, args); if (IsEvaluatingBatchSeemsToBeFinished) { UpdateLastFinished(); } LogState(); break; } }
private bool IsCalculatingTheSame(ExcelReference excelReference, AsyncCallInfo asyncCallInfo) { AsyncCallInfo cached; return(calculatingRefs_.TryGetValue(excelReference, out cached) && cached.Equals(asyncCallInfo)); }