I believe I have successfully created a plan which probably either contains a loop or contains interdependant relations.
However, I would believe this is rather ordinary and Projeqtor should handle gracefully. Instead, what happens is that PHP eats all available memory then crashes.
I am not a php coder so took some rather unholy amount of time to try to get a stack trace where this happens, so apologies for the format.
(The line numbers in
SqlElement.php
are a bit off since it was full of debug lines, but the function names shall be correct.)
This is after a few seconds. It runs for a few minutes, in the end the stack trace is.... long. And all the objects are on the stack, so multiply a huge object on stack by infinite number of recursions....
0:/home/projeqtor/projeqtor/model/persistence/SqlElement.php 786; SqlElement::getSqlElement 1:/home/projeqtor/projeqtor/model/PlanningElement.php 194; SqlElement::__construct 2:/home/projeqtor/projeqtor/model/ProjectPlanningElementMain.php 187; PlanningElement::__construct 3:/home/projeqtor/projeqtor/model/ProjectPlanningElement.php 39; ProjectPlanningElementMain::__construct 4:/home/projeqtor/projeqtor/model/persistence/SqlElement.php 3590; ProjectPlanningElement::__construct 5:/home/projeqtor/projeqtor/model/persistence/SqlElement.php 3555; SqlElement::getDependantSqlElement 6:/home/projeqtor/projeqtor/model/persistence/SqlElement.php 786; SqlElement::getSqlElement 7:/home/projeqtor/projeqtor/model/ProjectMain.php 220; SqlElement::__construct 8:/home/projeqtor/projeqtor/model/Project.php 40; ProjectMain::__construct 9:/home/projeqtor/projeqtor/model/persistence/SqlList.php 406; Project::__construct 10:/home/projeqtor/projeqtor/tool/projeqtor.php 4246; SqlList::getFieldFromId 11:/home/projeqtor/projeqtor/tool/projeqtor.php 3631; ::isOffDay 12:/home/projeqtor/projeqtor/tool/projeqtor.php 3603; ::removeWorkDaysToDate 13:/home/projeqtor/projeqtor/model/PlannedWork.php 2280; ::addWorkDaysToDate 14:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 15:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 16:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 17:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 18:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 19:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 20:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 21:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 22:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 23:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 24:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 25:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 26:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 27:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 28:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 29:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 30:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 31:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 32:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 33:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 34:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 35:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 36:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 37:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 38:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 39:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 40:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 41:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 42:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 43:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 44:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 45:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 46:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 47:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 48:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 49:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 50:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 51:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 52:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 53:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 54:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 55:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 56:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 57:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 58:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 59:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 60:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 61:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 62:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 63:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 64:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 65:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 66:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 67:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 68:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 69:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 70:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 71:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 72:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 73:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 74:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse 75:/home/projeqtor/projeqtor/model/PlannedWork.php 2243; PlannedWork::reverse 76:/home/projeqtor/projeqtor/model/PlannedWork.php 1883; PlannedWork::calculateCriticalPath 77:/home/projeqtor/projeqtor/tool/plan.php 62; PlannedWork::plan
Please run consitency check in Administrative screen.
It may find infinite loop issues.
Please run consitency check in Administrative screen.
It may find infinite loop issues.
Very unfortunately that was the first (few) things I have tried, and it finds everything to be just fine.
"No Issue Found" for all the checks.
Any other idea? Any manual checks? I surely have used a lot of criscrossed references but no intentional loops created, and I cannot even tell where it is (though I can suspect the task it crashes on).
About your traces, just add insformation to check if it is an infinite look, of just "long" execution.
For instance instead of writing
debugLog("PlannedWork::reverse");
try something like
debugLog("PlannedWork::reverse($nodeId,$idProject)");
So trace will be more explict : always the same or changing.
Possibly it is just long execution on large project on not too powerfull server 😉
About your traces, just add insformation to check if it is an infinite look, of just "long" execution.
For instance instead of writingdebugLog("PlannedWork::reverse");try something like
debugLog("PlannedWork::reverse($nodeId,$idProject)");
This output was created from a very full backtrace, so I have the full parameters in an 1.1 MB file.
You can retrieve it from here. It's a huge JSON plus a rude php code to print whatever you want to see from that mess, but it does contain the whole backtrace.
So trace will be more explict : always the same or changing.
Possibly it is just long execution on large project on not too powerfull server 😉
The project contains about 15 tasks, and a handful of everything, like a good test should.
The machine is, well, it is a container running on plenty of resources, but it's obviosuly looping since normal recalculation took about 500 ms and now it takes 5 minutes, about 50 times the memory and then crash, so I am fairly sure it's not the machine. 🙂
(Sidenote: I found Projeqtor a few weeks ago by accident, and I am still in awe how versatile and smart it is. I think I have tested most of the available project management code on Linux, and while your UI is not always the best, the code, feature-wise, is not even in the same universe as the others. I still try to get to know the various logic in Projeqtor, and I apologise in advance for my questions yet to come. :grin:)
Hi,
cannot examine your dump.
Please remove all other traces and keep only advised one.
Possible, if you use debugLog for other traces, use traceLog for this one and set logging level to trace.
Thanks.
Hi,
cannot examine your dump.
Why is that? Were you able to download? To unpack? The first line is a json, direct result of PHP's stack_dump(), if you remove the variable from the beginning and the closing quote and semicolon at the end. It contains all the calls with all the parameters, in order. I would think everything is there what you could possibly need.
Please remove all other traces and keep only advised one.
I do not understand. What should I remove, from where? What is "advised" and where? What are "traces"?
If you tell me, step by step, what would you like me to do I could do that, but I am not familiar with "traces", neither in projeqtor nor in php.
Possible, if you use debugLog for other traces, use traceLog for this one and set logging level to trace.
I will try to figure out how to set the logging level....
If you post some logs, please post textual file.
Not code or weird method...
There are too many lines, I cannot read that logs.
I guess these are not projeqtor log traces...
Just change log level in administration page to debug, add debig trace as requested and sen us projeqtor log file.
I feel there is a language barrier.
First: when I set the log level in Administration >> Log files maintenance to either Debug or Trace, nothing gets logged.
Second: what I sent to you is the fulles possible trace of a PHP calling stack. Let me expand one entry from it.
STACK: 46:/home/projeqtor/projeqtor/model/PlannedWork.php 2282; PlannedWork::reverse
This is the 46th call on the stack of the recursive function PlannedWork::reverse, which is at the 2282nd line of model/PlannedWork.php.
Following is the arguments of the reverse() function:
string(3) "E#6"
This is the first argument, called $nodeId.
The second argument is called &$cp (ref to $cp I guess), which is a large array of tasks(?) ordered reversed by end date(?). A sample:
array(3) {
["node"]=> array(40) {
["S"]=> array(4) {
["early"]=> string(10) "2023-01-09"
["late"]=> NULL
["before"]=> array(0) { }
["after"]=> array(10) {
[0]=> string(6) "S-S#20"
[1]=> string(5) "S-S#5"
[2]=> string(5) "S-S#9"
[3]=> string(6) "S-S#10"
[4]=> string(6) "S-S#11"
[5]=> string(6) "S-S#12"
[6]=> string(6) "S-S#16"
[7]=> string(6) "S-S#17"
[8]=> string(6) "S-S#19"
[9]=> string(6) "S-S#21"
}
}
["E"]=> array(4) {
["early"]=> string(10) "2023-11-01"
["late"]=> string(10) "2023-11-01"
["before"]=> array(7) {
[0]=> string(5) "E#8-E"
[1]=> string(5) "E#9-E"
[2]=> string(6) "E#10-E"
[3]=> string(6) "E#11-E"
[4]=> string(6) "E#12-E"
[5]=> string(6) "E#16-E"
[6]=> string(6) "E#17-E"
}
["after"]=> array(0) { }
}
["S#3"]=> array(4) {
["early"]=> string(10) "2023-08-01"
["late"]=> string(10) "2023-07-14"
["before"]=> array(1) {
[0]=> string(6) "#21-#3"
}
["after"]=> array(1) {
[0]=> string(2) "#3"
}
}
["E#3"]=> array(4) {
["early"]=> string(10) "2023-10-16"
["late"]=> string(10) "2023-09-28"
["before"]=> array(1) {
[0]=> string(2) "#3"
}
["after"]=> array(1) {
[0]=> string(5) "#3-#4"
}
}
["E#21"]=> array(4) {
["early"]=> string(10) "2023-08-01"
["late"]=> string(10) "2023-07-14"
["before"]=> array(1) {
[0]=> string(3) "#21"
}
["after"]=> array(1) {
[0]=> string(6) "#21-#3"
}
}
["S#20"]=> array(4) {
["early"]=> string(10) "2023-10-16"
["late"]=> string(10) "2023-09-28"
["before"]=> array(0) {
}
["after"]=> array(1) {
[0]=> string(3) "#20"
}
}
["E#20"]=> array(4) {
["early"]=> string(10) "2023-10-16"
["late"]=> string(10) "2023-09-28"
["before"]=> array(1) {
[0]=> string(3) "#20"
}
["after"]=> array(1) {
[0]=> string(6) "#20-#4"
}
}
["S#4"]=> array(4) {
["early"]=> string(10) "2023-09-28"
["late"]=> string(10) "2023-09-29"
["before"]=> array(2) {
[0]=> string(5) "#3-#4"
[1]=> string(6) "#20-#4"
}
["after"]=> array(1) {
[0]=> string(2) "#4"
}
}
["E#4"]=> array(4) {
["early"]=> string(10) "2023-10-30"
["late"]=> string(10) "2023-10-31"
["before"]=> array(1) {
[0]=> string(2) "#4"
}
["after"]=> array(1) {
[0]=> string(5) "#4-#8"
}
}
["S#5"]=> array(4) {
["early"]=> string(10) "2023-09-28"
["late"]=> string(10) "2023-08-10"
["before"]=> array(0) { }
["after"]=> array(1) {
[0]=> string(2) "#5"
}
}
["E#5"]=> array(4) {
["early"]=> string(10) "2023-10-04"
["late"]=> string(10) "2023-08-08"
["before"]=> array(1) {
[0]=> string(2) "#5"
}
["after"]=> array(3) {
[0]=> string(5) "#5-#6"
[1]=> string(5) "#5-#8"
[2]=> string(6) "#5-#13"
}
}
["S#6"]=> array(4) {
["early"]=> string(10) "2023-10-05"
["late"]=> string(10) "2023-08-09"
["before"]=> array(1) {
[0]=> string(5) "#5-#6"
}
["after"]=> array(1) {
[0]=> string(2) "#6"
}
}
["E#6"]=> array(4) {
["early"]=> string(10) "2023-10-08"
["late"]=> string(10) "2023-08-11"
["before"]=> array(2) {
[0]=> string(2) "#6"
[1]=> string(6) "#6-#19"
}
["after"]=> array(4) {
[0]=> string(6) "#6-#14"
[1]=> string(6) "#6-#18"
[2]=> string(5) "#6-#7"
[3]=> string(5) "#6-#8"
}
}
And the last argument is the $idProject:
["TEST"]=> string(2) "OK" } int(2)
The file is a serialized output of standard php debug_print_backtrace(), and I appended the code to deserialize it for you. From then on you have a structured object of the dump, which you can freely display. I have added a simple code to dump only the calls, but above I have showed you that you have the full stack trace of the endless recursive call.
Unfortunately I do not know what you call "E#13" or "S#15", as they do not seem to correlate with Activity id's, but you can see all the args, all the relations the reverse planner tried to resolve and failed, and you may able to spot (unlike me) what could possibly the bug in reverse planner which tries to infinitely recourse the args.
I would guess a developer only need to check one step (probably one from the end, like the above mentioned call 46, which is quite late in the recursion) to see where is the loop, and how reverse() could detect and prevent that.
Again, I am not php programmer, so it would take me much more time to reverse engineer PlannedWork.php than a developer of ProjeQtOr, that's why I kindly ask you to show the stack trace to a developer to make it possible to see the problem.
I do not know why the log does not log anything during this process, neither in Debug nor in Trace settings (and I have restored the original state of my modified code parts; it logs, for example, trace log from consistency checking): I only have apache telling me that it have crashed:
[Wed Oct 25 09:11:34.955321 2023] [php:error] [pid 1375439] [client 10.73.8.1:52436] PHP Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 262144 bytes) in /home/projeqtor/projeqtor/model/persistence/SqlElement.php on line 786, referer: https://projeqtor/view/main.php
The $cp contains the "nodes" of a "PERT" chart.
S#20 stands for start node of planning element 20
E#20 stands for end node of planning element 20
The #20 is the id of the planningelement referencing the item (activity, project, meeting, ...), that means where refType='Activiy' and refId=id of the Activity (for an activity)