{"action":"created","issue":{"url":"https://api.github.com/repos/SKCraft/Launcher/issues/82","labels_url":"https://api.github.com/repos/SKCraft/Launcher/issues/82/labels{/name}","comments_url":"https://api.github.com/repos/SKCraft/Launcher/issues/82/comments","events_url":"https://api.github.com/repos/SKCraft/Launcher/issues/82/events","html_url":"https://github.com/SKCraft/Launcher/pull/82","id":98074593,"number":82,"title":"Avoid pathological failure mode when trimming lines","user":{"login":"seebs","id":166725,"avatar_url":"https://avatars.githubusercontent.com/u/166725?v=3","gravatar_id":"","url":"https://api.github.com/users/seebs","html_url":"https://github.com/seebs","followers_url":"https://api.github.com/users/seebs/followers","following_url":"https://api.github.com/users/seebs/following{/other_user}","gists_url":"https://api.github.com/users/seebs/gists{/gist_id}","starred_url":"https://api.github.com/users/seebs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/seebs/subscriptions","organizations_url":"https://api.github.com/users/seebs/orgs","repos_url":"https://api.github.com/users/seebs/repos","events_url":"https://api.github.com/users/seebs/events{/privacy}","received_events_url":"https://api.github.com/users/seebs/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-07-30T02:53:39Z","updated_at":"2015-07-31T15:11:18Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/SKCraft/Launcher/pulls/82","html_url":"https://github.com/SKCraft/Launcher/pull/82","diff_url":"https://github.com/SKCraft/Launcher/pull/82.diff","patch_url":"https://github.com/SKCraft/Launcher/pull/82.patch"},"body":"If for any reason the document associated with a LimitLinesDocumentListener\r\nended up not getting shorter when its first line was removed (this is,\r\nof course, impossible), sklauncher would wedge in a busy loop that\r\ncompletely killed the GUI thread forever.\r\n\r\nSolution, part #1: Don't do a while loop, just remove multiple lines\r\nif you need to.\r\n\r\nBut wait, why are we having this problem at all? It turns out that there\r\nare problems when the document's length changes, which can manifest as\r\ntons of BadLocationExceptions going uncaught in the AWT thread which is\r\ntrying to refresh the window. Why? Probably because the insert into the\r\ndocument isn't happening in the Swing run queue, but concurrently with\r\nit. So use an invokeLater to do the actual insertion.\r\n\r\nWith these two changes, and a console set to 125 lines, I got no failures.\r\nPreviously, if I set the console to 125 lines, it would die catastrophically\r\nbefore Minecraft was done starting up.\r\n\r\nAlso performance may be noticably better. It's pretty common for things\r\nto dump 20+ lines into the buffer at once. If you have a 10,000 line buffer,\r\nand you then delete the first line of it 20 times, that's actually a whole\r\nlot of allocation and shuffling going on.\r\n\r\nMuch thanks to \"kenzierocks\" from IRC for helping debug this!"},"comment":{"url":"https://api.github.com/repos/SKCraft/Launcher/issues/comments/126721426","html_url":"https://github.com/SKCraft/Launcher/pull/82#issuecomment-126721426","issue_url":"https://api.github.com/repos/SKCraft/Launcher/issues/82","id":126721426,"user":{"login":"seebs","id":166725,"avatar_url":"https://avatars.githubusercontent.com/u/166725?v=3","gravatar_id":"","url":"https://api.github.com/users/seebs","html_url":"https://github.com/seebs","followers_url":"https://api.github.com/users/seebs/followers","following_url":"https://api.github.com/users/seebs/following{/other_user}","gists_url":"https://api.github.com/users/seebs/gists{/gist_id}","starred_url":"https://api.github.com/users/seebs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/seebs/subscriptions","organizations_url":"https://api.github.com/users/seebs/orgs","repos_url":"https://api.github.com/users/seebs/repos","events_url":"https://api.github.com/users/seebs/events{/privacy}","received_events_url":"https://api.github.com/users/seebs/received_events","type":"User","site_admin":false},"created_at":"2015-07-31T15:11:18Z","updated_at":"2015-07-31T15:11:18Z","body":"It is possible for the console to get into a state (possibly only on Windows?) where the console locks up completely, the launcher cannot refresh, the launcher uses 100% of a core of CPU time, and the Minecraft client is completely hosed because it has horrible problems every time it tries to write any output to its output streams.\r\n\r\nThe specific issue is that the client ends up in a state where removeFromStart() does not actually reduce the number returned by getElementCount(), meaning the while loop becomes an infinite loop.\r\n\r\nThis appears to be caused by a bug which is only exposed if the inserts collide with the rendering loop trying to access the same data, which causes an exception. But it also appears that the bug only shows up when you have \\r in the text, probably.\r\n\r\nThen once you get that fixed, there's a performance problem in that the launcher is spending a *ridiculous* amount of time on trimming strings. Consider what happens when an addon dumps a 31-line message to the log and the log is at 10k lines. The log is now at 10,031 lines. removeLines fires. It checks the line count, determines that it's high, calls removeFromStart(), which finds the length of the first line, and removes those characters. Now we're at 10,030 lines... And it has to do this 30 more times. And they may or may not involve allocations and copies, but there's certainly a lot of crap happening. (Even assuming we use the gap implementation for the document, the gap is getting slammed back and forth between end for the appends and beginning for the removes.)\r\n\r\nI honestly have no idea why the original implementation did a while loop there."}}