• DBA (unregistered)

    Developers like that should be kept away from a database as far as possible, and be discplined with a motivator (read: beaten with a stick).

  • Cico71 (unregistered) in reply to DBA
    DBA:
    Developers like that should be kept away from a database as far as possible, and be discplined with a motivator (read: beaten with a stick).

    Being a DBA, I do agree with you, especially on the motivator :-)

    However, we managed to keep them away so well that now they're coming back with all sorts of new square wheels like all the nosql thingamajig.

    There's no way to solve the problem: people don't like to study, they only want to pretend to be creative by re-doing everything from scratch.

    The only way out is to be sure to be retired before someone asks us to cleanup the "eventual consistency" mess that will pile up (as if we don't have already tons of bad data...)

  • Kasper (unregistered) in reply to Harrow
    Harrow:
    he was trying to grok the fundementals of asynchronous locking. Your advice sounds like "don't worry about it, it's a solved problem."
    I did go into a bit more detail, but we didn't have time to really go into the fundamentals. What I also did explain is that the fundamental solutions are only suitable for use within the operating system kernel, which is why you actually have to use what the platform provides for you, even if you know how to implement it from the bottom up. I did explain him about spinlocks and even how to make them perform better on hyperthreaded CPUs. I also explained how you can use Petersons algorithm if you need to do locking on hardware where there are no CPU instructions to perform an atomic read/write operation. I think I also mentioned how the scheduler will pick another process to run while one is blocked.
  • L. (unregistered) in reply to net.split
    net.split:
    So I did something kind of like this once as a newbie, except it was much more brutal. I made a simple web game back in college (complete with SQL scattered across PHP files, oh god it was bad). Some enterprising players found out they could refresh the page really fast to gain lots of benefits without spending resources more than once.

    My solution? Put a lock on the player's account at the start of every page load, then remove it at the end of the script. Every time a page script started, it checked to see if the lock was there; if it was, then it would stop with an error page.

    What if there was an error in the script? The player was locked out of the game until some amount of time passed (about 5 seconds).

    What if different users kicked off race condition processes? Then something probably broke.

    In my defense, I was using MySQL prior to 5, which did not support transactions. But still.

    Using MySQL is not in your defense .. it goes showing that you are not a DBA and have a lot to learn in the field ;)

    Seriously . MySQL was a WTF before InnoDB, and it's STILL a WTF even with InnoDB. It's not ACID compliant, most of the implemented features are half-implemented at the incorrect layer (like trying to make something reliable on top of an unreliable engine ...)

    Anyone who uses MySQL and does not recognize that it is altogether a failure of a DBMS should not call themselves DBA.

    F*ck MySQL, it's a noob webdev's toy, not a database.

  • L. (unregistered) in reply to versioning?
    versioning?:
    It doesn't need to be that complex, and you don't really need to do much validation. Put a version number on each record and send the version number back to the HTML page. When the user submits the modification request "update ..., version=version+1 where version=LAST_VERSION_SEEN and ..." and check how many records were changed. Wrap all the actual updates (only on submit) in a transaction and roll those back to notify the browser if anything changed.

    So added complexity is:

    1. A transactional update and rollback which you should have anyways.
    2. A single version number on each table, which is returned in every form
    3. An additional condition in every where clause
    4. A single sql%rowcount after every update statement.

    I'm sure there are other solutions but that is pretty easy to implement.

    Dude. you suck.

    That way of doing things is retarded . like way retarded. but w/e .. if you want to reinvent the squared wheel, feel free to explain to everyone how to do it ...

    Seriously, when you don't understand what you're doing, don't give any fricken advice !

    Do you have any clue how much of an issue it is for noob devs coming later on and reading/believing your crap ???

    1. Not necessarily. Update/Rollback ??? WHY DID YOU F****ING UPDATE IN THE FIRST PLACE YOU GODDAMN ... leprechaun (random word replace)

    2. Yes.. because user A needs to be notified when he edits CI #226587 of table T -- that user B edited CI # 287675 ... Right ! put on the smartypants for victoryyy !

    On the friggin table .. really. that makes so much sense I would personally cut your hands to prevent you from typing anything like that or touching anything like a database.

    1. WTF ??? WHY ??? yes I would like two liters of additional conditions for my where clauses, thx dude.

    2. A single sql rowcount .?? WHAT THE F*CK ???? WHY ? omg . you are so .. brilliant I should consider giving you a promotion.

    Now ... back to WHAT you were trying to achieve ... you wish to handle some CC manually through users in order to avoid blind overwrite of states, i.e. S1->S3->S2 wtf-type.

    The "transactions" from the human point of view are :

    read S1 edit write S2

    AND:

    read S1 edit write S3

    The only thing you need to do is to make sure currentstate=S1 just before you write S2 or S3.

    As you provided your application with S1 info prior to the edit, you have a good basis for comparison.

    Thus, when you send your 'write' instruction, you will simply verify that the stored state matches S1 (not with a query unless you know your types are perfect - much better off if you do it in your server-side code as type transformations through the SQL connector might not be failsafe).

    Well, so you do this :

    Read S1

    Edit (manual human op)

    Read CurrentState (write lock - select for update)

    if(S1==CurrentState){ update }else{ alert('wtfhaxx : S1 =, CurrentState=') } release lock

    Then if it failed, the user gets to keep his edited info, consult the CurrentState, makes changes he wants, posts it back with an S1 now equal to the last retrieved data (i.e. CurrentState).

    Seriously . takes more time to write than to figure out --

    Also, I do contracting work in case you need someone how actually knows what he's doing --

  • L. (unregistered) in reply to Saepius
    Saepius:
    Daniel Smedegaard Buus:
    That's really cute :)

    Although it'd be interesting to see the kind of SQL operations he wants to do after his "locking system" lets him continue. A transaction provides atomicity, but doesn't protect against race conditions. Two simultaneous updates using transactions will still mean one update "disappearing". But, even if it's this problem he's trying to solve, he should be using an SQL table lock to solve it, not this homebrewed SELECT thing which has exactly the same problem. Maybe he should try doing it three times in a row for extra-extra safety ;)

    You know how I know you're a MySQL user?

    1. SQL transactions DO protect against race conditions. On SQL server (non snapshot) by locking records that have been read. With snapshot (or on oracle) by checking database values haven't changed between transaction start and commit, and raising an error if they have.

    2. Table locks are not normally used in anything but MySQL, as transactions lock the relevant parts of the tables as needed.

    Capitalizing on your remark, I would like to offer the TDWTF troll community a new meme to replace "TRWTF is VB" which is not getting much love these days anyway ..

    "TRWTF is MySQL" or "TRWTF is people who use MySQL" or "TRWTF is MySQL"

    God bless the toy database for noob webdevs !

  • (cs) in reply to DBA

    I think that "disciplined with a motivator" sounds too strict. How about "...encouraged to onboard the appropriate value-system through proactive reward-based coaching...". (Sorry - I sit within earshot of HR... :-).

  • An Old Hacker (unregistered) in reply to DaveK
    DaveK:
    An Old Hacker:
    As mentioned, there are times when home-brew transactions are required. Such as when you are writing a memory manager for an all-assembly micro OS.

    Here's how its done, and you can actually get by even if you lack atomic in the underlying system.

    1. Enter the fact that you want a lock into a the queue. (Since we're talking databases, use an auto incrementing key.)
    And if we aren't talking databases (but say for example are writing a memory manager for an all-assembly micro OS) what happens when two threads try to "enter the fact that [they] want a lock into the queue" at the same time? How do they avoid racing if you "lack atomic in the underlying system"? All the lock-free designs I know about rely on having an atomic compare-and-swap instruction available.

    Starting at the end, the only reason I can imagine to write an all-assembler OS is if you are doing microprocessor validation (which I was). In that case, you cannot trust the microprocessor to get everything right, and the lock instructions are complicated.

    Now, you are correct that a normal queue is subject to the same sort of contention issues as any other access. If you have an ACID database, there is an easy enough solution to the problem. Working with memory, however, the "queue" is implemented as a series of bytes. Each thread gets a byte. Single-byte writes don't mess with their neighbors. As long as you can read all the bytes for all the threads at once, you can tell who has their hand raised. Turning that into a proper queue requires some additional paperwork, which, in the above list, which is maintained as part of the lock release.

    If you can't read them all at one time, you nest. :-E

  • An Old Hacker (unregistered) in reply to Junkyard Science
    Junkyard Science:
    An Old Hacker:
    1) Enter the fact that you want a lock into a the queue. (Since we're talking databases, use an auto incrementing key.) 2) Wait until there is no one ahead of you in the queue. 3) Wait until the lock clears. 4) Write the lock with your id. 5) Do your stuff. 6) Clear your lock. 7) Remove yourself from the queue.
    Congratulations, you've just implemented a semaphore in a database... There are ways to handle locking and exclusiveness in ACID databases. Using home-brew is not one of them. Using any home-brew semaphore and locking mechanisms in a database is likely to be a significant cause if lock contention and therefore very poor performance.

    First, all I did was read the paper & adapt it. No congratulations needed. Second, I never advocated using such a solution for any particular problem. I was concerned that people reading the comments might believe that some of the proposed solutions were adequate, and wanted to set the record straight.

    BY ALL MEANS, use builtins when you can. (And if you can't, try harder.) But if you insist on home-brew, the above will work.

  • tegh (unregistered)

    Most probably the worst thing I have ever seen...

  • Brendan (unregistered) in reply to Cico71
    Cico71:
    Brendan:
    In general; locks (when done right) are always at least as good as transactions or better than transactions in terms of performance/scalability.
    I'm not sure why you consider locks and transactions as two different means to accomplish a given thing.
    Probably because they're two different means to accomplish a given thing.

    Transaction = do a bunch of work (while tracking what you relied on to do the work) in the hope that you can commit the result, then try to commit the result (and fail if you detect that something you relied on changed in the meantime).

    Locks = get any lock/s needed to guarantee you can do the work, then do the work.

    Of course there's no reason why you couldn't mix locks and transactions to get a hybrid scheme with the disadvantages of both techniques.

    The transaction isolation levels look like a feeble attempt to avoid some of the overhead of "foolproof" (serializable) transactions by breaking consistency guarantees (and therefore creating something that aren't true transactions and don't meet ACID rules). The existence of isolation levels is an admission that "foolproof" (serializable) transactions suck for performance/scalability (and that the performance is so bad that the risks associated with allowing consistency guarantees to be broken/ignored are justified).

  • (cs) in reply to An Old Hacker
    An Old Hacker:
    Junkyard Science:
    Congratulations, you've just implemented a semaphore in a database... There are ways to handle locking and exclusiveness in ACID databases. Using home-brew is not one of them. Using any home-brew semaphore and locking mechanisms in a database is likely to be a significant cause if lock contention and therefore very poor performance.

    First, all I did was read the paper & adapt it. No congratulations needed. Second, I never advocated using such a solution for any particular problem. I was concerned that people reading the comments might believe that some of the proposed solutions were adequate, and wanted to set the record straight.

    I think Junkyard Science was thrown by your use of the parenthetical "(Since we're talking databases, use an auto incrementing key.)" and missed the earlier "Such as when you are writing a memory manager for an all-assembly micro OS."

  • Se (unregistered) in reply to DaveK
    DaveK:
    An Old Hacker:
    As mentioned, there are times when home-brew transactions are required. Such as when you are writing a memory manager for an all-assembly micro OS.

    Here's how its done, and you can actually get by even if you lack atomic in the underlying system.

    1. Enter the fact that you want a lock into a the queue. (Since we're talking databases, use an auto incrementing key.)
    And if we aren't talking databases (but say for example are writing a memory manager for an all-assembly micro OS) what happens when two threads try to "enter the fact that [they] want a lock into the queue" at the same time? How do they avoid racing if you "lack atomic in the underlying system"? All the lock-free designs I know about rely on having an atomic compare-and-swap instruction available.

    You turn off interrupts :-P

  • John_R (unregistered)

    In db__locks, fill in the __ with "ol" and you will solve the puzzle.

  • Spikkel (unregistered)

    If you ever should decide on not using transactions (where I don't see any reason at all for), you could as well write it good.

    For example you can write your lock as:

    1. a delete on each processid that doesnt have a connection anymore
    2. an insert where you include the caller and the processid of the connection with a unique constraint on the object you want to lock.
    3. Followed by a select => if its your processid and caller then you got the lock. Otherwise you didn't.

    It's definitely slower than transactions, and it only solves the locking issue and you can't rollback unless you build in something for that too. But at least this should work so you wouldn't need an "admin" tool.

    Can I advice strongly against this approach? :-)

  • Neil (unregistered) in reply to Planar
    Planar:
    Dekker [1] solved this problem in the early 60s, then Peterson [2] came up with a much simpler solution. Both rely on atomic writes and reads.

    Then Lamport [3] solved the problem without any atomic primitive (i.e. even if the underlying system doesn't provide atomic writes and reads). But you should fetch some aspirin before you try to read that paper.

    [1] (Link redacted by Akismet) [2] (Link redacted by Akismet) [3] (Link redacted by Akismet)

    [3] http://en.wikipedia.org/wiki/Lamport's_bakery_algorithm
  • bob (unregistered)

    Complete moron code.

    1. It locks a FULL table..... a morons excuse for time wasting.
    2. it uses a table to hold the state, if the system goes down, then the table is still intact on startup, with the other tables locked
  • Jay (unregistered) in reply to dtech
    dtech:
    So what are those 17 previous examples of where solving the meta-problem actually was effective?

    Only thing I can think of are the Bytecode->Assembly->3rd gen->Managed code transistions, even if those are meants that's only 4.

    Maybe Relational databases (from flat-files) too

    Depends on your definitions, I suppose, but off the top of my head I'd certainly list:

    1. Von Neuman machines (stored program computers)

    2. Assembly language

    3. Compiled languages

    4. On-line text editors

    5. Structured programming

    6. Object-oriented programming

    7. Automated debuggers

    8. Integrated development environments

    9. Network Databases

    10. Relational databases

    11. Source code control

    At a lower level I can think of things like:

    1. "families" of microchips that share a common machine language

    2. cross-assemblers and cross-compilers

    I'm sure with a little thought one could come up with many similar meta-solutions in the IT world.

  • DirkAndTheMac (unregistered) in reply to JDege

    I'm hoping this is a joke.... if not...... TRWTF!

  • Piper Tom (unregistered)

    The humility of the story's first paragraph is overwrought. World hunger?! I posit that most of the world's hunger is caused by politics, not by technical means -- but set that aside. It's not even remotely possible that one person is going to "solve" a problem having literally billions of details. But thousands or millions of good people can each make tiny contributions that add up to immense improvement. This relates to ordinary programmers: you make a change to the way other people work; it's a little less costly or a little less error prone. Fewer resources are spent or lost by these others, leaving them more time or money (or stuff!) to do other things. The gain is all in the margins; you cannot trace it, but it's there and adds to the other gains made by others doing similar things. You CAN see the accumulation: the tools and methods of 1000 BCE could feed only a few million people, but the tools and methods today can feed a few billions. Rejoice in your part of that.

  • (cs) in reply to JDege
    JDege:
    you provide some sort of validation, prior to the save
    <sarcasm> Yes, that might be a good idea </sarcasm>
  • RodMan (unregistered)
    -- Reset @@rowcount to zero
    UPDATE 1=0 WHERE 1==0
    
    -- Run until @@rowcount is NOT zero
    WHILE @@rowcount == 0
      BEGIN
        UPDATE LockLevel = '1'
          FROM db__Locks
         WHERE LockTbl = 'GL_Operations'
           AND LockLevel == '0'
    
         IF @@rowcount == 0 WAITFOR DELAY '00:00:01'
      END
    
    IF @@rowcount != 0 ERROR 'UPDATE(ed) too many/too few rows %d', @@rowcount
    

    There, fixed it for ya. Now it is atomic .... transactions, trans-smack-tions. Now to write a database monitor to catch deadlocks. Then to write a monitor to look for orphaned locks. Maybe I need to add a un?x pid and SQL pid to the db__Locks table? Then we need to add rollback vs. commit logic. What else? Maybe clustering, raid, and striping would be a good thing (TM) to add? This could get good, keep ya in work for a long time. What a brilliant developer, Robert Rossney should thank him profusely!

    :-p

  • ccj (unregistered)

    I think the wikipedia topic he was looking for was 'semaphore'. Also, why in the world would you try to implement an asynchronous process management system in a query language (especially when it already has Transactions built in behind the scenes)?

    captcha: "ideo" ideo killed the adio star!

Leave a comment on “Classic WTF: I Think I'll Call Them "Transactions"”

Log In or post as a guest

Replying to comment #:

« Return to Article