[google-appengine] Re: New bill did not draw from my Discounted Instance Hours pool

2011-11-10 Thread Murph
If you're on Python, the cheapest option is currently 0 discounted hours, 
as the normal frontend hours are already discounted, until December.

Current rates are:

Python Frontend: $0.04/hour  (normal rate $0.08/hour)
Discounted hours: $0.05/hour

Unless I've missed something?

-- 
You received this message because you are subscribed to the Google Groups 
Google App Engine group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/google-appengine/-/8-xZS6YNQDQJ.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.



Re: [google-appengine] Re: The Dining Philosophers

2011-10-27 Thread Murph
I think it's basically possible to do locking, mutexes, semaphores, etc in 
memcache, by taking advantage of some of the semantics, plus the new-ish 
compare  store stuff.  There's the obvious caveat that it could be flushed 
without warning, or disabled for a while, so it's not a high reliability 
thing.

  def add(self, key, value, time=0, min_compress_len=0, namespace=None):
Sets a key's value, iff item is not already in memcache.

  def replace(self, key, value, time=0, min_compress_len=0, namespace=None):
Replaces a key's value, failing if item isn't already in memcache.

  def cas(self, key, value, time=0, min_compress_len=0, namespace=None):
Compare-And-Set update.

  def incr(self, key, delta=1, namespace=None, initial_value=None):
Atomically increments a key's value.

  def decr(self, key, delta=1, namespace=None, initial_value=None):
Atomically decrements a key's value.

It seems to me the you could carefully use the above in various creative 
ways to implement this, if you require frequent use and the datastore costs 
would be prohibitive for it.

-- 
You received this message because you are subscribed to the Google Groups 
Google App Engine group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/google-appengine/-/cAlYR6jxlogJ.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.



[google-appengine] Re: Datastore update without read

2011-10-11 Thread Murph
You can't update just a single property/attribute of an entity unless you 
already know the values for all of the others.  If it's frequently updated, 
careful use of memcache may allow you to avoid the db.get, but otherwise you 
have to read it first.

An alternative, if you just have say 1 property/attribute which changes 
often would be to split the entity into two separate entity models, one with 
the relatively static data, and the other with the frequently changing 
data.  The downside there, of course, is that you're going to have 2 db.get 
operations when you need all of it, instead of 1.

Internally, the datastore is entirely composed of (key, value) pairs, with a 
single (key,value) per entity (not counting indices, metadata, etc), and the 
SDK encodes/decodes those values into your entity models for you.  They are 
actually encoded as protobufs, but there's nothing in the datastore's API to 
modify that data without reading it first.

-- 
You received this message because you are subscribed to the Google Groups 
Google App Engine group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/google-appengine/-/e6JrqffTES4J.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.



[google-appengine] Re: Keeping sensitive information in memory

2011-10-05 Thread Murph
To be honest, if any part of the GAE servers are compromised, they have your 
entire application (everything you've uploaded) and data right there, if 
they have full control over the server host.  Securing the system's memory  
swap is not going to offer terribly much at that point.

This is just somewhere you're going to have to trust Google to get the 
security perimeter of the servers and network absolutely perfect.  If 
trusting them with that is too high a risk for your data, then frankly you 
shouldn't be on GAE, and probably shouldn't be on any external cloud 
solution.

-- 
You received this message because you are subscribed to the Google Groups 
Google App Engine group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/google-appengine/-/JtKmw95VAkQJ.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.



[google-appengine] Re: Change Class of Polymodel Instance

2011-10-04 Thread Murph
Here's a method I've discovered for changing the class on PolyModel, which I 
think is relatively clean:

ent1 = Model1.get(…)  # Or get_by_id, etc
dict = db.to_dict(ent1)
del dict['class']
# Other changes to dict, as required, adding/removing properties
ent2 = Model2(key=ent1.key(), **dict)
ent2.put()

I think that's fairly clean, although I've not used it heavily.

-- 
You received this message because you are subscribed to the Google Groups 
Google App Engine group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/google-appengine/-/-CAdxp8LpocJ.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.



[google-appengine] Re: Need Python example of Template System

2011-10-04 Thread Murph
You should probably use some other template system (e.g. django.template), 
as webapp.template is going to be deprecated soon.

-- 
You received this message because you are subscribed to the Google Groups 
Google App Engine group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/google-appengine/-/kvBZWObe1t0J.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.



Re: [google-appengine] Change Class of Polymodel Instance

2011-10-04 Thread Murph
Nick, any comment on my approach of changing the PolyModel's class via 
db.to_dict and creating a new model with the same key?  That seems to me 
like a relatively clean  safe way to do it.  The desire to be able to do 
this for my case, is to be able to move records from Person to User, then 
User to SuperUser, gaining extra fields needed as the person descends the 
hierarchy.  I suspect that's a fairly common scenario, and seems almost 
exactly the type of thing that PolyModel was designed for.

-- 
You received this message because you are subscribed to the Google Groups 
Google App Engine group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/google-appengine/-/O3DQBp7xtBAJ.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.



[google-appengine] Re: Managing Dev and Live versions

2011-09-29 Thread Murph
You should also take a look at multitenancy / namespaces (same feature, 2 
different names for it).

http://code.google.com/appengine/docs/python/multitenancy/

I'd guess it can also be done in Java, my GAE experience is all Python.  In 
Python, you setup the default namespace for a request in your 
appengine_config.py based on more or less whatever logic you want, so easy 
to do it based on the URL hostname prefix.  The namespace effectively gives 
a soft partitioning of the datastore  memcache (I say soft, as it's 
possible for a request handler to access all namespaces, if it wants to).

-- 
You received this message because you are subscribed to the Google Groups 
Google App Engine group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/google-appengine/-/Pk1TxNpIgz8J.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.



[google-appengine] Re: Assigning datastore IDs based on UUIDs from an external DB

2011-08-09 Thread Murph
After a little testing, I discovered a flaw in my previously posted 
technique, namely that it was generating uint64 IDs, when the datastore will 
only accept non-zero uint63s.  I'd also forgotten to include my UUIDProperty 
class.  Here's the updated version.  The question remains whether there's 
likely to be any horrible loss of efficiency or problems by assigning IDs 
which will be essentially randomly distributed through the possible number 
space (the external DB mostly uses UUIDv4, so the distribution should be 
quite random).  As previously stated, auto-assigned IDs will not be used for 
these models, so collisions or disruption of auto-assignment are not a major 
concerns.  The code probably still needs the odd bit of polishing here and 
there.

MASK_64 = 2**64-1
MASK_63 = 2**63-1


class UUID(uuid.UUID):
# Could use this, but Python doesn't guarantee future stability of
# hash values
# def get_id(self):
# return abs(hash(self.int))

def get_id(self):
 Returns a positive, non-zero 63 bit integer from the
UUID's int128 
x = ((self.int  MASK_64) ^ (self.int  64))  MASK_63
if (x == 0):
x = 1
return x

id = property(get_id)


class UUIDProperty(Property):
A UUID property, stored as a 16 byte binary string.

data_type = UUID

def get_value_for_datastore(self, model_instance):
uuid = super(UUIDProperty,
 self).get_value_for_datastore(model_instance)
return ByteString(uuid.bytes)

def make_value_from_datastore(self, value):
if value is None:
return None
return UUID(bytes=value)

def validate(self, value):
if value is not None and not isinstance(value, self.data_type):
try:
value = self.data_type(value)
except TypeError, err:
raise BadValueError('Property %s must be convertible '
'to a %s instance (%s)' %
(self.name, self.data_type.__name__, 
err))
value = super(UUIDProperty, self).validate(value)
if value is not None and not isinstance(value, self.data_type):
raise BadValueError('Property %s must be a %s instance' %
(self.name, self.data_type.__name__))
return value


class UUIDModel(Model):
@classmethod
def get_by_uuid(cls, uuids, **kwds):
uuids, multiple = datastore.NormalizeAndTypeCheck(uuids, (UUID, 
str))
def normalize(uuid):
if isinstance(uuid, str):
return UUID(uuid)
else:
return uuid
uuids = [normalize(uuid) for uuid in uuids]
ids = [uuid.id for uuid in uuids]
entities = cls.get_by_id(ids, **kwds)
for index, entity in enumerate(entities):
if entity is not None and entity.uuid != uuids[index]:
raise BadKeyError('UUID hash collision detected (class %s): 
'
  '%s / %s'
  % (cls.kind(), entity.uuid, uuids[index]))
if multiple:
return entities
else:
return entities[0]

@classmethod
def get_or_insert_by_uuid(cls, uuid, **kwds):
if isinstance(uuid, str):
uuid = UUID(uuid)
id = uuid.id
def txn():
entity = cls.get_by_id(id, parent=kwds.get('parent'))
if entity is None:
entity = cls(key=Key.from_path(cls.kind(), id,
   parent=kwds.get('parent')),
 uuid=uuid,
 **kwds)
entity.put()
elif entity.uuid != uuid:
raise BadKeyError('UUID hash collision detected (class %s): 
'
  '%s / %s'
  % (cls.kind(), entity.uuid, uuid))
return entity
return db.run_in_transaction(txn)

uuid = UUIDProperty('UUID')

-- 
You received this message because you are subscribed to the Google Groups 
Google App Engine group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/google-appengine/-/BEkUAv6h6icJ.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.



[google-appengine] Assigning datastore IDs based on UUIDs from an external DB

2011-08-05 Thread Murph
Hi folks,

I've been pondering the best approach to modelling objects where the objects 
in my GAE datastore correspond to a subset of objects in an external DB 
where primary keys are UUIDs.  As I expect most of my records in GAE to 
really be quite small, I feel it's worth avoiding the storage size overhead 
of just using the 36 character UUID as the key_name, and have come up with 
the following to generate datastore uint63 IDs from UUIDs (Python, but the 
questions are more general GAE efficiency questions):

MASK_64 = 2**64-1

class UUID(uuid.UUID):
def get_id(self):
return abs((self.int  MASK_64) ^ (self.int  64))

id = property(get_id)

class UUIDModel(Model):
@classmethod
def get_by_uuid(cls, uuids, **kwds):
uuids, multiple = datastore.NormalizeAndTypeCheck(uuids, (UUID, 
str))
def normalize(uuid):
if isinstance(uuid, str):
return UUID(uuid)
else:
return uuid
uuids = [normalize(uuid) for uuid in uuids]
ids = [uuid.id for uuid in uuids]
entities = cls.get_by_id(ids, **kwds)
for index, entity in enumerate(entities):
if entity is not None and entity.uuid != uuids[index]:
raise BadValueError('UUID hash collision detected!')
if multiple:
return entities
else:
return entities[0]

@classmethod
def get_or_insert_by_uuid(cls, uuid, **kwds):
if isinstance(uuid, str):
uuid = UUID(uuid)
id = uuid.id
def txn():
entity = cls.get_by_id(id, parent=kwds.get('parent'))
if entity is None:
entity = cls(key=Key.from_path(cls.kind(), id,
   parent=kwds.get('parent')),
 uuid=uuid,
 **kwds)
entity.put()
elif entity.uuid != uuid:
raise BadValueError('UUID hash collision detected!')
return entity
return db.run_in_transaction(txn)

uuid = UUIDProperty('UUID')

I won't be using GAE's auto-assigned IDs for the model classes which have 
IDs assigned from the external DB's UUID, so I'm not terribly worried about 
the probability of ID collision, as 2**63 is still a very large number space 
compared to the number of records that I expect to have.  My reason for 
using a custom hashing of the UUID into a uint63 is because Python's hash 
function isn't guaranteed to remain consistent with future Python versions.  
The reason for using uint63 is because the datastore classes throw an 
exception on negative int64s used as IDs.  Had the datastore supported 
int128 or uint127 for IDs, I would have just used the UUIDs more directly 
with it.  I'm using the UUID as the GAE key to allow direct get_by_id() 
calls when I already know the UUID, rather than having to do a filtered 
query on it.

So, on to the questions.  The above seems to work just fine for me in early 
prototype stages of development, but I'm wondering if there's a downside to 
this technique?  Will I hit any performance, space, or general efficiency 
penalties with the datastore by using IDs which are essentially randomly 
assigned throughout the entire 63bit ID space?  Is there anything about this 
which strikes people as a terrible idea and would justify me having a major 
rethink about my approach?  What techniques are others using when they have 
externally assigned UUIDs as primary keys for some of their model classes?

-- 
You received this message because you are subscribed to the Google Groups 
Google App Engine group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/google-appengine/-/IqEKH0ZY5BkJ.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.