Setup for
trebuchet's yduJ's MOO Lore Pamphlet (#2364)
.
Object setup.
Object name:
trebuchet's yduJ's MOO Lore Pamphlet
Location:
trebuchet (#2773)
Parent:
yduJ's MOO Lore Pamphlet (#1893)
Owner:
trebuchet (#2773)
Description:
There appears to be some writing on the note...
Physical setup.
Anchor:
unanchored
Key/lock:
unreadable
Note setup.
Text:
yduJ's MOO Lore Pamphlet -- -- -- lagyduJ's Theory Of LagWhat causes lag? This is a perennial question on LambdaMOO. There two basictypes of lag: Net lag, and CPU lag. Net lag is lag you experience betweenyour local computer (whatever's connected to the keyboard) and the remotecomputer (LambdaMOO), and can have lots of causes.Net lag is usually different for different players, depending on theirdistance from the MOO. Distance isn't necessarily in miles---someone 10 milesfrom the MOO machine behind a 14.4kbaud SLIP line may have higher lag thansomeone in New York sitting on a machine with a T1 line. People on othercontinents than the MOO typically have higher netlag than those in NorthAmerica, because their bits have to get funneled through some narrow channelunder an ocean, competing with the propagation ofalt.binaries.pictures.erotica, or have to go up to a satellite and back downagain, which takes a while.LambdaMOO, however, primarily suffers from CPU lag. This means the source ofthe problem is on the computer that's running the MOO itself, and no amount ofcloseness to the MOO is going to help fend it off. There are several thingswhich can cause CPU lag, and lambdamoo suffers from them all.When a program takes more memory than the machine has physical memory, it usesthe disk to make memory look bigger, and does what's called "paging" to switchstuff back and forth. This makes stuff way slower. LambdaMOO's physicalmemory is 256 meg (that's bigger than most people's hard drives), but theprogram is about 330 meg, so it doesn't fit. Surprisingly, measurements haveshown that LambdaMOO's machine isn't paging very much, though it is pagingsome.But the main thing that's going on with LambdaMOO is that there is just toomuch work for the poor little thing to do. There are frequently 250 peoplelogged in at once, and if they're all typing, in order to execute within 1second lag, it has to do 250 commands per second. This is a lot, because torun the MOO language, the computer has to do a fair amount of work. To makematters worse, there are usually about 350 queued "forked tasks" competingwith the 250 logged in users. Adding this all up makes for a very busycomputer and very bad lag.So what's my theory of what makes lag worse? My theory is that it takes a lotmore time to create a forked task than you think. (Note: suspending creates atask too, but fork is the real killer.) My theory is that if one is doing alot of work, and suspending at regular intervals, you should use up your wholequantum of ticks, and call :suspend_if_needed(60), giving the machine a wholeminute to ignore you and run someone else's stuff. It needs the break by then!You should also be very careful when writing loops that you're not computingthe same data twice. Store data in properties, and update the propertiesincrementally, rather than recomputing whole reams of stuff for differentpeople.If you're doing something that's periodic, emitting a message into a room, forexample, make it with a really long period. Nobody cares to see the skychange color every 10 seconds; every 5 minutes is good enough. And make surethere's someone to *see* your text. Don't write tasks that sit in thebackground and change the color of the sky, even every 5 minutes, if there'snobody there to watch. Use :enterfunc to start tasks, and check on :exitfuncwhether you should be stopping them. If you have something that changes itsdescription based on a time factor, don't make a task to change thedescription. Instead, when the object is looked at, have it quickly computewhat *would have happened* had there been a task changing it. You may think"but my task only goes once every five minutes!" Yes, that's true. Butyou're sharing the machine with 8,000 other people, and once every fiveminutes is way more than your share. Stamp out periodic tasks!If you're triggering on something like :tell, if you should fork() (a definiteno-no!), make sure you are running only one task at a time. Record thecurrently running task in a property on the object. In the next iteration,check $code_utils:task_valid and don't fork if it's valid. -- -- -- permissionsPermissions are problematical in MOO. Generally you don't need to beconcerned with permissions unless you are trying allow others to createchildren of your generic objects. However, most serious MOO programmers endup doing this, so it's worth knowing how the permissions work.Let's use as example the Generic Wind-up Toy from our previous tutorial, onlythis time we'll have a different user, Eiram, create the child object, Wind-upSushi. @create #12221 named Wind-Up Sushi,Sushi You now have Wind-Up Sushi (aka Sushi) with object number #15666 and parent Generic Wind-Up Toy (#12221).The default for creating a child object is that the new owner owns not onlythe object, but all of the properties as well. For example, let's look at.wind_down_msg, on the generic, and on our new child: @show toy.wind_down_msg #12221.wind_down_msg Owner: yduJ (#68) Permissions: rc Value: "finishes." @show sushi.wind_down_msg #15666.wind_down_msg Owner: Eiram (#40068) Permissions: rc Value: "spasms once and stops spinning."We see that yduJ, who owns the generic, owns the property. But on the child,the owner of that object owns the property.Here's the tricky part. Only the owner of a property may change thatproperty. This changing owner on a property makes a lot of sense for thingslike messages. You wouldn't want yduJ to be able to change Eiram's sushi'smessages, just because she owns the generic.However, we'll recall that the windup toy has a property .wound that it setsand decrements as it runs.The way that verb permissions work is that they run as though the person whowrote the verb was doing all the work (with the author's permissions), not asthough the person who issued the verb call was doing the work, or as theperson who owns the object that initiated the verb. You could imagine any ofthese three possibilities. The second one would be more like Unix. In unix,for example, it matters who is typing "cat file", not who wrote the catprogram. This allows for trojan horses to be installed in the cat program bypeople with questionable moral systems. The MOO system is somewhat lessflexible, but more secure. Since it matters who wrote the verb, players knowthat their own properties and objects are safe from would-be crackers. (Unixfolks can think of verbs as always running "setuid".)However, this means that if the .wound property were treated the same as the.wind_down_msg property, then the :wind verb (which was written by yduJ, andthus can only change properties owned by yduJ) wouldn't be able to change theproperty on Eiram's sushi. Thus, you'd wind and wind, but it wouldn't everget wound up. Similarly, the verb that winds down wouldn't be able todecrement the .wound property, so the sushi would run forever! (Really, inboth cases it would instead crash with a permissions error, but still, neitherfate is acceptable.)Let's talk about that Permissions: line in the @show above. Propertypermissions are stored as a string of characters, one or zero each from theset "rwc". R means readable; any verb can just do local =#15666.wind_down_msg and have the value assigned into the string. If the "r"bit is not set, only the owner of the property can look at it. W meanswritable; any verb can *change* the property. This is extremely rare, becauseof the possibility for abuse. C means "change in children", and is the oneresponsible for causing Eiram to have become the owner of the .wind_down_msgwhen he did @create. If you simply remove the "c" bit from a property, thecopies in children don't get changed to the owner of the child object, butstay as the person who defined them on the generic. So, before letting Eirammake a child object, yduJ did: @chmod toy.wound !c Property permissions set to r.And now when we use @show: @show toy.wound #12221.wound Owner: yduJ (#68) Permissions: r Value: 0 @show sushi.wound #15666.wound Owner: yduJ (#68) Permissions: r Value: 0We see that yduJ is the owner of this property. Note that this means Eiramcan't change that property, despite owning the object it is on! Read the entryon Security in order to learn how to deal with this problem. -- -- -- primitivesYou can't really program on LambdaMOO just from reading the manual. Readingthe manual gives you excellent background on how the underlying server works,but really, in the LambdaCORE, there are some verbs which take the place of(really, enhance the features of) the primitives defined by the server.notify(person,message) => person:tell(message);move(object,place) => object:moveto(place);read() => $command_utils:read() or $command_utils:read_lines()In addition to direct replacements defined for all objects, there are anenormous number of utility verbs designed to make programming tasks easier.'Help Utilities' gives you a starting point to the documentation on theutilities; there are a lot of them!Proselytizing here a bit:create() => #4455:_create()recycle() => #4455:_recycle()Read recycling in #23456 for more information. -- -- -- schedulerHow does the scheduler work?The idea is there is a round robin queue of player tasks. That means that eachplayer gets no more and no less CPU than any other. It just takes them one ata time, in order.Within that timeslice, each player gets eir own round robin of forked tasks,including the interactive task that e may be typing at. (E may be logged out,and still have tasks, so it isn't necessary that there be an interactive taskin the list.)I think of it as a two dimensional array, or maybe a list each element ofwhich is a bunch of lists. You go around the big list, taking the top itemfrom the sublists each time. The sublists get added to by fork. You get a newinteractive task for each command, so that adds to it, but also subtracts fromit. Suspend moves the tasks to the end of your little list. The big list getsadded to only when a player not currently in the list has a task started (e.g.with an automatic trigger in a room, or by connecting to the MOO).So by having a large number of tasks ready to run, a player spams eirself,giving eirself a noticeable lag, which supposedly are not felt by players withonly one task. Large numbers of cpu-intensive tasks can spam the entire MOO,though, impacting even those players who are being socially responsible withtask use.There's another wrinkle: If a player does a lot of computation even if e hasfew forks, that amount of computation is remembered, and when e comes up againfor round robin scheduling, e may be skipped based on that large amount ofcomputation, until someone else has built up a similar quantity, or therearen't any other tasks waiting. (I don't understand the exact algorithm here;the short of it is if you see "out of seconds", go get coffee---you'reblackballed for a while---maybe several minutes.) -- -- -- securityRead the entry on Permissions to understand how property permissions work.In many cases, both the property owner (verb/generic author) and the owner ofthe child object will need to be able to change a property. MOO does not have"multiple ownership", or "permission groups", or any of those sorts of things. The typical solution to this problem is for the generic owner to provide acallable verb :set_whatever. Sometimes it is appropriate to also provide acommand line verb such as @set-whatever, depending on the application. Thesesetting verbs then generally need to have security in them, to make sure thatnobody but the child owner and generic owner actually make any changes. Sohere's some blathering on what are the available options:The variable "caller" is like "this" from the calling verb. If you check forcaller == this, you can be sure that the calling verb was defined either onthis object or on one of its parent hierarchy. For verbs which are pass()edto, caller == this is true. If there wasn't a caller because this is thefirst verb executed in the command, then caller is the same as player. Youmight use caller == this as your security check if you want to make sure thatthe :set_whatever verbs are only called by the child objects, or your ownverbs. caller doesn't let you distinguish between being called by a verbdefined on the generic or a verb defined on the child.caller_perms() gives you the permissions of the calling verb (usually theperson who wrote the calling verb). Note that permissions are represented byplayer objects, so when I say "the verb was called with my permissions" thatmeans caller_perms() == #68. Only a wizard-authored verb can change thepermissions that a verb runs with; see documentation on the functionset_task_perms() if interested. Basically, you can use caller_perms() to seeif someone is trying to spoof your verb. Check caller_perms() == this.ownerto make sure only the proper person is calling the verb. Caller_perms() is#-1 if your verb was invoked directly from the command line; sometimes youwant to have a verb that's callable by another verb, *or* straight from thecommand lines, and still be able to do security checks. So, you use: valid(caller_perms()) ? caller_perms() | playerwhere you'd have just used caller_perms() in a verb not command line callable. This idiom can also be used in a wizardly set_task_perms() call.Wizards think it's nice if your verbs that do various permissions checkingsallow wizards to use your verbs, even if they don't own the object. You canuse $perm_utils:controls(person,object) instead of using a == this.owner typecheck... Wizards can bash your object anyway, it's just more convenient forthem if you don't get in their way. :-) Seriously, on LambdaMOO, a lot ofpeople make errors in their code and their object needs to be rescued; it'snice if you make these janitorial jobs easier.callers() is another way you can do security checking. It tells you a lot ofinformation about exactly how this verb got called. Do help callers() formore info... I always forget how it works, so whenever I'm writing a verbthat uses callers(), I get the help, and then I write the verb with a player:tell($string_utils:print(callers()))so I can see just what I'm getting... I recommend this sort of experimentaldata gathering. Some people hate callers(). They think that for every use ofcallers() there is one verb that's doing two jobs, and it should be separatedout into two verbs. In most cases they're right. If you're using callers()to determine how your verb should behave, rather than as a security thing,think about restructuring your code.One sweeping method of security is to make your verb !x. This means it can*only* be invoked from the command line. However, this also means it canneither be called from a program nor be pass()ed to, which is sad, becausesomeone might want to customize the behavior of this command line verb.Remember, use args of "this none this" to prevent a verb from being invokedvia the command line. A !x "this none this" verb can't be called in any way(and thus is totally pointless!) A +x verb with a normal arglist can becalled from anywhere. Read about arglists in the programmer's manual.You'll note that I've never used "player" except in the caller_perms() casewhere I knew the verb had been invoked from the command line. This is becauseplayer is basically completely useless, from a security point of view. Playeris the person who typed the original command which set in motion the thread ofcontrol which eventually lead to your verb getting called. This doesn't mean"player called your verb".I'm going to describe how to spoof player in a :tell. I wrestled with myselffor a long time about whether I would do this in this document. So, here itis. This type of spoofing is considered at least an order of magnitude morerude than the usual sort. You've been warned..program me:tellpass(@args); /* do the normal stuff */if (player == <my enemy>) dobj = player; #9060:bonk();endif.So, everytime my enemy makes a noise in my presence, e bonks eirself with thecarrot, because it's really too hard to eschew the use of "player" in VRsettings such as the bonker. 99% of the time it's correct; indeed, it's onlyincorrect in cases where someone is trying some funny business. Thisdemonstration shows how using "player" for security checking is totallyuseless; the whole point of security checking is to prevent people from doingthings they shouldn't, which means that you have to assume these people willbe trying tricks such as the above. For example, if the name setting codedidn't have caller/caller_perms() security checks, I could have calledplayer:set_name("IamAnIdiot") instead of merely being a pain with the bonker.
Encryption:
unreadable
Update and repair this object.
Check this object's web page with the W3 HTML 4.0 validator.
Destroy this object utterly and irretrievably.
You are not
logged in
.
[
home
|
help
|
who
|
search
|
setup
|
code
]