Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
Yet another Unique Key generator
Message
De
22/11/1999 12:14:46
 
Information générale
Forum:
Visual FoxPro
Catégorie:
Base de données, Tables, Vues, Index et syntaxe SQL
Divers
Thread ID:
00293537
Message ID:
00293957
Vues:
22
>>>In your first response you said, "Yes. There is nothing to prevent two people from getting the same key value." Do you have any support for that claim?
>>>
>>>>You didn't get it. The problem is not with the UPDATE, but the original INSERT. There is nothing to stop two people from inserting the same record.
>>>
>>>Yes there is: it would cause a primary key violation of the KeyCtr table.
>>
>>Carl,
>>
>>At this point all I'm going to say is use it if you want. I would not rely on it to work. My method has been tried and tested by people all over and works perfectly.
>
>Craig,
>
>I would have dropped this, but I think you will want to know that there is a problem with your code. I am using the version found at http://members.home.net/foxpro/kb/kb0006.html
>
>SEEK UPPER(tcTable)
>IF FOUND()
> liRetVal = NextId
> REPLACE NextId WITH NextId + 1
>ELSE
> INSERT INTO Keys (Table, NextId) VALUES (tcTable, 2)
> liRetVal = 1
>ENDIF
>
>You seek upper(), but Insert the base value. If you pass in a mixed case table name, "For example, GetKey("Client")", It always will fail the seek, and try and insert it again, which violates the primary key of Keys.
>
>You may also want to know the results of some time tests. The code below found that in a low traffic environment (no contention) mine was at least 5 times as fast, and in a high traffic it was still over 10% faster. I am surprised with the second result, I figured that locking would meter the allocations and smooth out the contentions. Let me know if you can create an environment where yours is faster, I am interested in what I missed.
>
>set func 10 to "canc;clear prog;do "+sys(16)+";"
>close database all
>
>* set coverage to ("mkkey"+substr( sys(0), 1, 2)+".log" )
>set talk off
>
>if !file( "test.dbc" )
>
> create database test
>
> create table KeyCtr ;
> ( kKeyCtr c(30) primary key, ;
> nCtr i )
> create table test1 ;
> ( kTest i primary key default MkKey( "test.kTest" ) )
>
> create table KEYS ;
> ( Table c(20) primary key, ;
> NextID i )
> create table test2 ;
> ( kTest i primary key default GetKey( "test.kTest" ) )
>
> close database
>
>endif
>
>?
>? datetime()
>
>use test!test1 shared
>* Wait for file 'start' to get created (echo>start1)
>? "waiting for start1"
>do while !file('start1')
>enddo
>ltSrt = datetime()
>for lnI = 1 to 1000
> append blank
>endfor
>? datetime() - ltSrt
>
>use test!test2 shared
>* Wait for file 'start' to get created (echo>start2)
>? "waiting for start2"
>do while !file('start2')
>enddo
>ltSrt = datetime()
>for lnI = 1 to 1000
> append blank
>endfor
>? datetime() - ltSrt
>
>close databases all
>set coverage to
>return
>
>function MkKey( tcFld )
>
>local ;
> llDone
>
>llDone = .f.
>do while !llDone
>
> * Get the current value of the Counter for this key
> select nCtr ;
> from KeyCtr ;
> where kKeyCtr = tcFld ;
> into array laCtr
>
> if _tally = 0
> * If we didn't get one, there is no counter yet.
> * So make one and try again
> debugout "Added Key Counter: " + tcFld
> insert into KeyCtr ( kKeyCtr, nCtr ) values ( tcFld, 0 )
> loop
> endif
>
> * Bump the counter.
> * The counter holds the next key value, we use the original value
> * The kKeyCtr identifies which counter,
> * the nCtr make sure noone else has bumped it allready
> update KeyCtr ;
> set nCtr = laCtr[1] + 1 ;
> where kKeyCtr = tcFld and nCtr = laCtr[1]
>
> if _tally = 0
> * The update failed.
> * Probably because someone other process has grabbed the same key,
> * and bumped the counter first.
> * So we will try again.
>* debugout "Counter assignment contention at " + transform( laCtr[1] )
> * Close the KeyCtr table to assure a fresh version of the key counter data.
> * Otherwise, we get the same key from the buffer, not a new one from disk.
> use in KeyCtr
> loop
> endif
>
> * Once we get to here, we have a good new key.
> llDone = .t.
>
>enddo
>
>return laCtr[1]
>
>
>FUNCTION GetKey
>LPARAMETERS tcTable
>
>LOCAL lnArea, llOpened, liRetVal
>
>* Save current work area
>lnArea = SELECT()
>llOpened = .F.
>
>IF !USED("Keys")
> USE Keys IN 0 SHARED
> llOpened = .T.
>ENDIF
>SELECT Keys
>SET ORDER TO TAG Table
>
>* FLOCK seems to work a bit better than RLOCK.
>* I've never had a problem with it.
>DO WHILE !FLOCK()
>ENDDO
>
>SEEK tcTable
>IF FOUND()
> liRetVal = NextId
> REPLACE NextId WITH NextId + 1
>ELSE
> INSERT INTO Keys (Table, NextId) VALUES (tcTable, 2)
> liRetVal = 1
>ENDIF
>
>FLUSH
>UNLOCK
>
>IF llOpened
> USE IN Keys
>ENDIF
>
>SELECT (lnArea)
>RETURN liRetVal

Not if you INDEX ON UPPER(Table) TAG Table. Works every time. IMO, Character fields should always be indexed on UPPER() to avoid these kinds of problems that you are describing. I can't tell you the exact number of people using my code, but it is quite a few and no one reports problems.
Craig Berntson
MCSD, Microsoft .Net MVP, Grape City Community Influencer
Précédent
Répondre
Fil
Voir

Click here to load this message in the networking platform