Bug #25281

(SQF) Empty procedures and dead pipe

Added by sparcdr over 3 years ago. Updated over 3 years ago.

Status:New Start date:10/08/2011
Priority:Normal Due date:
Assignee:firefly2442 % Done:

0%

Category:Arma2MySQL
Target version:- Estimated time:2.00 hours

Description

There seems to be an issue with the handler "splitting" a nul/empty string (CBA-related); I have a procedure called GetAllUIDs which requires no arguments, so I tried omitting the third sendProcedure column, which failed (Since it needs it, though it shouldn't), so I changed the third parameter to an empty "", where it sent and received the array fine, but the pipe remained blocked and subsequent query of the same command resulted in nil.

The pipe loop should reset "main" upon thrown exception in the C# side, since unintended datasends may crash it, resulting in potential loss of data/ability to use.

I played around a bit with the All-in-one code framework from Microsoft, using the CSNamedPipeServer/Client examples as a reference, and I simply had it re-call the pipe listener method when it dropped. Though it's been a while, so I don't have an example, what I did was abstract any looping logic outside of the main routine so it could be re-called, including sanitation of the hung pipe.

Explicit termination of the pipe may be necessary with in-game logic, so a specific way to globally do such should be documented. This goes hand-in-hand with the C# logic "resetting" itself.

A timeout within the loop "waiting" should be either an optional parameter or part of the routine, since weird crap happens on the arma-side when scripts bomb out.

- James

History

Updated by sparcdr over 3 years ago

Also, I noticed another cause of s/null/no response is uniqueness of the IN parameter.

SQL_Cfg_Saving_GetAllUIDs = {
_ret = [];
_arr = ["theapp", "GetAllUIDs", "n=1"] call asff_arma2mysql_fnc_sendProcedure;
player groupChat format["%1", _arr];
_ret;
};

If I run call SQL_Cfg_Saving_GetAllUIDs twice, it only returns once, but if I change 'n=1' to 'n=somethingelse' it returns fine.

I use n as a null paramter for IN to prevent CBA strsplit bombing.

Updated by sparcdr over 3 years ago

_arr = ["theapp", "GetAllUIDs", format["n=%1", round(random(time))]] call asff_arma2mysql_fnc_sendProcedure;

Is a definitive way of randomizing the IN parameter.. Subsequent uses should never block due to what I explained in the previous reply, though given ARMA's random maths being unreliable at times, the only saving factor of using time as a source is the fact it's a (3 decimal) floating point.

Updated by firefly2442 over 3 years ago

  • Assignee set to firefly2442

Hmm interesting. I'm not sure I follow all of this as it sounds like you tested and came up with many issues, however, I'll definitely check it out. I have noticed that the pipe does seem to hang sometimes. After initialization and connection, if the Arma mission finishes, the pipe never closes. I'm not sure if this is a new issue in Jayarma2lib or not but...

Would you be interested in helping out with development on this? I can add read/write access to Git if you like.

Updated by sparcdr over 3 years ago

The issue doesn't exist in jaylib if you explicitly terminate the pipe every iteration, using a global variable on a loop to check if the pipe is nil (With some modest timing spice), which circumvents the illusion that it's hanging, when it's actually just "stuck" in a "wait for" condition, when the pipe has already ~attempted to negotiate the send to ARMA2 over the pipe..

It's stuck not because of code compile issues on the ARMA side, nor because of a failure to handle the string on the pipe side, however from my tests with more real-time-esc scripting of pipes earlier on (I used the CSNamedPipeServer example before as I stated) indicated the proper and only workable way that won't result in the pipe nulling is to greedily close and re-create the pipe by re-instancing the method after implicitly closing it on the C# side.. (Attempting to do so on the ARMA side as well with a timeout) Win32 named pipes have (When using marshalling / native invocation) like TCP/IP a timeout parameter, which may be something to look at.

I was able to successfully do sends repeatedly to infinity (Forever loop) without loss of the handle by simply closing it.. since the pipes are to be used usually by one 'giant lock' (Single loop) on the server-side, with global conditions describing the state, it's not unreasonable to simply make your data routines in SQF conform to that notion, instead of expecting a forever-open pipe to actually stay that way, when it really doesn't want to.

Additional implications would suggest that if you needed concurrent pipe access, you'd need separate pipes running, so an array of pipes to handle the requests via threads is probably the more reasonable approach, since this project is specifically for mysql uses, the only modifications would be the names of the pipes and the target, which could be stored in a parsed ini or xml file for the lay.

I don't know how much time I could contribute, but I'll consider requesting formal access later on, when I can actually come up with some possible fixes, or a different approach to submit, but until then I don't think it's necessary to provide Git access.

Updated by sparcdr over 3 years ago

You can't close the pipe on mission end unless there's some super secret eventhandler for such.. there isn't. Only the lack of transmission can be used as a fuzzy source for discerning that condition.

Also, another thought I had was about the 4k limit... one would have to have additional get procedures to get count to estimate maximum length to overcome that limit in ARMA. Pretty crap situation.

Updated by sparcdr over 3 years ago

I fixed GetAllUIDs function btw.

Function -
SQL_Cfg_Saving_GetAllUIDs = {
_ret = [];
_time = format["n=%1", round(random(time))];
_arr = ["theapp", "GetAllUIDs", _time] call asff_arma2mysql_fnc_sendProcedure;
if ((typeName(_arr) == "ARRAY") && (count(_arr) >= 1)) then {
for [{_i = 0}, {_i < count(_arr)}, {_i = _i + 1}] do {
_uarr = _arr select _i;
_uid = _uarr select 0;
_ret set[count(_ret), _uid];
};
};
_ret;
};

Invocation -
_uids = call RPM_Cfg_Saving_GetAllUIDs;

SQL -
DROP PROCEDURE IF EXISTS `GetAllUIDs`;
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `GetAllUIDs`(IN `n` int(1))
BEGIN
SELECT uid from accounts;
END
;;
DELIMITER ;

Updated by Jman over 3 years ago

I have come across a related issue when returning an empty MYSQL field with a default value of NULL. The result is that the wrapper crashes when returning the data.
I was able to work around this.

Updated by Jman over 3 years ago

  • Category set to Arma2MySQL

Also available in: Atom PDF