I want all of my db interactions for a specific model to go through the mongo primary in my cluster, so I set the model to use strong consistency.
class Photo
include Mongoid::Document
with consistency: :strong
field :number, type: Integer
# let's say a photo number is unique in the db
validate :unique_number
end
But this does not seem to work, because I still run into validation errors when I save two Photo photos very close together.
photo1 # db has number=1 for this object
photo1.update_attributes(number: 2)
photo2.number = 1
photo2.save! # <= this raises a validation exception
My understanding of strong consistency is that there shouldn't be a race here. It should do the write and then do the read, and since it's all off the primary there shouldn't be a conflict. What am I missing?
What you area experiencing looks like it is persistence. The update_attributes is making an atomic change on the document, and it looks like it is not updating the persisted photo1.Your photo2 validation is fired from within the persistence (i.e. on the rails server and not in mongo) and is looking at the records it has. If you ran photo1.reload after the photo1.update_attributes this may sort this for you.
It's been a while since I used mongoid 3, 4 has been the staple for a while and recently upgraded to 5.You won't find this type of issue in mongoid 4.
If the reload does not help, please output photo2.errors so I can pin point the issue for you.
It turns out calling with(consistency: :strong) at the class level only applies it to the next query. So the class method is called when the class is loaded, setting strong consistency for the first query,
but subsequent queries don't trigger the same class method leaving their persistence operations to operate with eventual consistency. From the Mongoid 3.1.7 documentation:
Tell the next persistance [sic] operation to store in a specific collection, database or session.
This method does not enforce the persistence options that can be passed in (like a few other methods in the class), so we can also pass in consistency: :strong.
Hack Fix
In order to apply this to every* persistence operation, I added it to a default_scope.
class App
default_scope -> { with(consistency: :strong); where({}) }
end
In this case, the default scope expects to have a Mongoid Criteria object returned, so we return a noop where clause after setting the consistency level on the in-progress persistence operation.
* This will not be applied if the developer decides to call unscoped and strip off the default_scope.
Related
When editing a form, the user may sometimes not change the form and still click the submit button. In one of the controller methods below, will the save() method perform a query to the database and update the fields even if the user didn't change anything?
PostMapping("/edit_entry/{entryId}")
public String update_entry(
#PathVariable("entryId") Long entryId,
#RequestParam String title,
#RequestParam String text
) {
Entry entry = this.entryRepo.findById(entryId).get();
if (!entry.getTitle().equals(title))
entry.setTitle(title);
if (!entry.getText().equals(text))
entry.setText(text);
this.entryRepo.save(entry);
return "redirect:/entries";
}
And also, are the "if" statements necessary in this case?
What exactly happens during a call to save(…) depends on the underling persistence technology. Fundamentally there a re two categories of implementations:
Implementations that actively manage entities. Examples of this are JPA and Neo4j. Those implementations keep track of the entities returned from the store and thus are able to detect changes in the first place. You pay for this with additional complexity as the entities are usually instrumented in some way and the change detection of course also takes time even if it ends up not detecting any changes. On the upside though the only trigger updates if needed.
Implementations that do not actively manage entities. Examples are JDBC and MongoDB. Those implementations do not keep track of entities loaded from the data store and thus do not instrument them. That also means that there is no way of detecting changes as all the implementation sees is an entity instance without any further context.
In your concrete example, a MongoDB implementation would still issue an update while JPA will not issue an update at all if the request params do not contain differing values.
For testing reasons, I want to check that one of my methods doesn't update a specific entry in my database. Is there a simple way to ask an instance of an ActiveRecord model if its in sync with the database? for instance, if we had a method foobar? that could do this:
old_post = Post.find(1)
updated_post = Post.find(1)
updated_post.update_attributes(name: "this is a new name not like the old name")
old_post.foobar? #should return true, as its attributes are no longer up to date
updated_post.foobar? #should return false, as its attributes match the database directly
So is there a method that acts like foobar, or something like it? Thanks in advance.
I think your problem lies beyond finding a method which tells you wether an attribute has been updated, but in the relationship among the different objects that are instantiated. First it is important to understand, that old_post and updated_post are unrelated ruby objects. They know about how to save their own state to the database, but they do not know about each other.
Therefore your first requirement for foobar? cannot be fulfilled, as old_post will think it is up-to-date as long as no attribute has been updated. In contrast the changed? method will roughly answer in the way you are trying to achieve for updated_post. However it does so because it thinks nothing has happened since it was last saved, this will not be verified against the database upon each call of changed? as this would be wasting a database call in 99.9% of all cases.
This means it is all too easy to generate anomalies between the objects you created as there is no direct connection between the two (except the implicit connection that they once represented the same database row). If you change an attribute in one object (using e.g. title='?' it will change the value of the object and take note of the change in the changed-array. Once you save this object it will save its changed attributes to the database (by creating an individually constructed update-statement).
Another object that is already instantiated (as old_post in your example) will not know about this change and might change other attributes if you are not careful (or even the same ones if they have been changed again). Depending on your database adapter you may try to use the lock! method which will synchronize your object with the database before allowing any modifications. This however will not happen automatically as in most controller methods updates do not conflict nearly often enough to merit the synchronization as it will be idempotent in most cases.
This does not go without saying that rails can not save you from thinking about your transaction semantics if you want to guarantee specific ACID semantics for your controller methods.
I'm using DataMapper as ORM framework after many years of experience with AR. For that reason I sometimes try to find a specific DM function that mirrors some behaviour from AR. Sometimes I'm lucky, sometimes I'm not. With the #reload directive, I'm kind of in a limbo. The method exists, but somehow doesn't do what I expected it to. Basically, instead of the AR behaviour in which the instance attributes would be updated looking up to the DB, DM somehow marks every attributes from the instance as "not loaded".
Can somebody tell me if this is possible to achieve using DM?
DataMapper marks the attributes as not loaded and will load them on the next access.
This is a result from support of lazy loading groups. DM-1 will wait to see what attribute is accessed next to load only a limited set of attributes.
Per default all attributes are in the :default group, so most likely all attributes are loaded once you hit one.
In case this lazy behavior is not wanted you can do the following:
resource = YourClass.first(:some => :stuff)
# full non lazy reload (make sure you do not have
# a reference to old somewhere that causes confusion
resource = resource.model.get(resource.id)
I'm wanting to dynamically create and query tables using Datamapper.
While Datamapper allows you to work with legacy tables and schemas, and in this way set the table name used this is only during initialisation, not within the application.
Is there an easy way to tell Datamapper to migrate/upgrade a Model with an assigned table name in application, and to then tell it to query this table?
This should not be a problem.
All Ruby classes can be created, and re-defined at run-time. Even initialization is at run-time. Initialization just happens to be executed first, before other code is executed.
That is why monkey-patches work so easily. It's just additional code at initialization that just re-defines classes to add extra methods, variables etc.
There is no Ruby code that is "special" in the sense that it only runs at compile time. Ruby is an interpreted language.
To dynamically create a class, see Dynamically creating class in Ruby.
Assuming you don't need to dynamically create classes from an array of strings, you can define additional methods with define_method, or call Datamapper methods at runtime to add attributes.
To define new methods in a class:
Post.send :define_method, :new_method_name do
end
To define a new property using the Datamapper property:
class Post
include DataMapper::Resource
property :title, String # the static way
end
Post.send :property, :title, String # add property the dynamic way (at run-time)
Do note that any tables or properties you define at run-time will not be available if you restart your server, unless the code that dynamically generates these are re-executed.
To update your tables at runtime, you simply do the same thing as normal, that is, call:
DataMapper.auto_upgrade!
To upgrade only a single table, you can also do:
Post.auto_upgrade!
2nd warning: If you have multiple processes, the dynamic code will need to be run in each process, or the additional table Models and Properties will not be available.
This is a problem if you have multiple worker processes, as might happen in production (eg. Nginx with multiple Unicorn workers, or multiple Mongrel workers behind a Ha_proxy).
If you have a single process server, then that is not a problem. However, if you have multiple worker processes, you must run the dynamic code to generate these extra classes and properties in EACH process to make it available.
This is actually the same for initialization, because each process goes through initialization (or if forked, inherit any initialization).
The easiest way without changing anything under the hood is to use separate databases instead of tables (assuming that any relationships will also be stored in the separate database) and open a connection to an additional repository in the block.
DataMapper.setup(:external, "adapter://username:password#hostname/dbname")
DataMapper.repository(:external) do...end
I am designing a class for log entries of my mail server. I have parsed the log entries and created the class hierarchy. Now I need to save the in memory representation to the disk. I need to save it to multiple destinations like mysql and disk files. I am at a loss to find out the proper way to design the persistence mechanism. The challenges are:
How to pass persistence
initialization information like
filename, db connection parameters
passed to them. The options I can
think of are all ugly for eg:
1.1 Constructor: it becomes ugly as I
add more persistence.
1.2 Method: Object.mysql_params(" "),
again butt ugly
"Correct" method name to call each
persistance mechanism: eg:
Object.save_mysql, Object.save_file,
or Object.save (mysql) and
Object.save(file)
I am sure there is some pattern to solve this particular problem. I am using ruby as my language, with out any rails, ie pure ruby code. Any clue is much welcome.
raj
Personally I'd break things out a bit - the object representing a log entry really shouldn't be worrying about how it should save it, so I'd probably create a MySQLObjectStore, and FileObjectStore, which you can configure separately, and gets passed the object to save. You could give your Object class a class variable which contains the store type, to be called on save.
class Object
cattr_accessor :store
def save
##store.save(self)
end
end
class MySQLObjectStore
def initialize(connection_string)
# Connect to DB etc...
end
def save(obj)
# Write to database
end
end
store = MySQLObjectStore.new("user:password#localhost/database")
Object.store = store
obj = Object.new(foo)
obj.save
Unless I completely misunstood your question, I would recommend using the Strategy pattern. Instead of having this one class try to write to all of those different sources, delegate that responsibility to another class. Have a bunch of LogWriter classes, each one with the responsibility of persiting the object to a particular data store. So you might have a MySqlLogWriter, FileLogWriter, etc.
Each one of these objects can be instantiated on their own and then the persitence object can be passed to it:
lw = FileLogWriter.new "log_file.txt"
lw.Write(log)
You really should separate your concerns here. The message and the way the message is saved are two separate things. In fact, in many cases, it would also be more efficient not to open a new mysql connection or new file pointer for every message.
I would create a Saver class, extended by FileSaver and MysqlSaver, each of which have a save method, which is passed your message. The saver is responsible for pulling out the parts of the message that apply and saving them to the medium it's responsible for.