[Glass] About GsDeployer new doBulkMigrate

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

[Glass] About GsDeployer new doBulkMigrate

Mariano Martinez Peck
Hi gemstoners,

I have just finished reading "Chapter 10 - Class Creation, Versions, and Instance Migration" but when I was about to start writing some scripts I found GsDeployer. I found this very interesting expression: "GsDeployer new doBulkMigrate".

I am not 100% sure of what it does, so please confirm if I understand correctly:

1) it searches each class of symbol list of current user that has more than 1 in the class history
2) it migrates each version of each found class to the last one from the history. And this migration is the basic ones... I mean, new instVars in new class will be with nil, and old instVars not existing in new class will be dropped, etc.
3) committs etc..

So...is that correct? If true, then it means that if I don't have any specific migration matter (like instVar renaming, or initialize some new instvar with some state that depends on old value, etc etc etc), that would migrate everything automatically, right?

But...if that's correct...I need to be very very very careful in executing such a migration since after the migration I will have lost all previous class versions and more importantly, I will have lost instVars from old classes in the case new class does not define them. Correct? 

Thanks in advance,

--
Mariano
http://marianopeck.wordpress.com

_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: [Glass] About GsDeployer new doBulkMigrate

Dale Henrichs-3
Mariano,

You are correct, but once you've migrated all of your instances forward, you don't need the classes in your class history ...

The other thing to watch for when doing bulk migrations is executing code during the load that might REQUIRE all instances to be migrated ... the migrations are not done until the end of the load  ... the classic example is Monticell itself ... back when I was actively finding and fixing bugs in the Monticello loaders the new methods were being sent to old instances so i _had_ to migrate during the load ...

As a final comment ... if for some reason you mess up your class history, it should be possible to rebuild the class history from the instances of the old class ... while it is something you don't want to do ... it's worth keeping in mind that it can be done in an emergency:)

Dale


On Wed, Apr 16, 2014 at 12:05 PM, Mariano Martinez Peck <[hidden email]> wrote:
Hi gemstoners,

I have just finished reading "Chapter 10 - Class Creation, Versions, and Instance Migration" but when I was about to start writing some scripts I found GsDeployer. I found this very interesting expression: "GsDeployer new doBulkMigrate".

I am not 100% sure of what it does, so please confirm if I understand correctly:

1) it searches each class of symbol list of current user that has more than 1 in the class history
2) it migrates each version of each found class to the last one from the history. And this migration is the basic ones... I mean, new instVars in new class will be with nil, and old instVars not existing in new class will be dropped, etc.
3) committs etc..

So...is that correct? If true, then it means that if I don't have any specific migration matter (like instVar renaming, or initialize some new instvar with some state that depends on old value, etc etc etc), that would migrate everything automatically, right?

But...if that's correct...I need to be very very very careful in executing such a migration since after the migration I will have lost all previous class versions and more importantly, I will have lost instVars from old classes in the case new class does not define them. Correct? 

Thanks in advance,

--
Mariano
http://marianopeck.wordpress.com

_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass



_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: [Glass] About GsDeployer new doBulkMigrate

Mariano Martinez Peck



On Wed, Apr 16, 2014 at 7:38 PM, Dale Henrichs <[hidden email]> wrote:
Mariano,

You are correct, but once you've migrated all of your instances forward, you don't need the classes in your class history ...


Yes.
 
The other thing to watch for when doing bulk migrations is executing code during the load that might REQUIRE all instances to be migrated ... the migrations are not done until the end of the load  ... the classic example is Monticell itself ... back when I was actively finding and fixing bugs in the Monticello loaders the new methods were being sent to old instances so i _had_ to migrate during the load ...


And how did you do that? (migrate during load) 
 
As a final comment ... if for some reason you mess up your class history, it should be possible to rebuild the class history from the instances of the old class ... while it is something you don't want to do ... it's worth keeping in mind that it can be done in an emergency:)


Ahhhh of course...the migrate stuff "just" changes the class pointer of the instances right? So if the slots for XXX instVars were there...they won't get lost. I guess it is similar to Pharo's #adoptInstance: and #primitiveChangeClassTo: 
Good!
 
Dale


On Wed, Apr 16, 2014 at 12:05 PM, Mariano Martinez Peck <[hidden email]> wrote:
Hi gemstoners,

I have just finished reading "Chapter 10 - Class Creation, Versions, and Instance Migration" but when I was about to start writing some scripts I found GsDeployer. I found this very interesting expression: "GsDeployer new doBulkMigrate".

I am not 100% sure of what it does, so please confirm if I understand correctly:

1) it searches each class of symbol list of current user that has more than 1 in the class history
2) it migrates each version of each found class to the last one from the history. And this migration is the basic ones... I mean, new instVars in new class will be with nil, and old instVars not existing in new class will be dropped, etc.
3) committs etc..

So...is that correct? If true, then it means that if I don't have any specific migration matter (like instVar renaming, or initialize some new instvar with some state that depends on old value, etc etc etc), that would migrate everything automatically, right?

But...if that's correct...I need to be very very very careful in executing such a migration since after the migration I will have lost all previous class versions and more importantly, I will have lost instVars from old classes in the case new class does not define them. Correct? 

Thanks in advance,

--
Mariano
http://marianopeck.wordpress.com

_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass





--
Mariano
http://marianopeck.wordpress.com

_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: [Glass] About GsDeployer new doBulkMigrate

Dale Henrichs-3



On Wed, Apr 16, 2014 at 4:31 PM, Mariano Martinez Peck <[hidden email]> wrote:



On Wed, Apr 16, 2014 at 7:38 PM, Dale Henrichs <[hidden email]> wrote:
Mariano,

You are correct, but once you've migrated all of your instances forward, you don't need the classes in your class history ...


Yes.
 
The other thing to watch for when doing bulk migrations is executing code during the load that might REQUIRE all instances to be migrated ... the migrations are not done until the end of the load  ... the classic example is Monticell itself ... back when I was actively finding and fixing bugs in the Monticello loaders the new methods were being sent to old instances so i _had_ to migrate during the load ...


And how did you do that? (migrate during load) 

Are you sure that you want to know? ... haha ... actually over the lifetime of GLASS I've attempted all sorts of hacks installing missing methods as part of preload, putting in error handlers in the new code to do the right thing, and crossing my fingers:)

Probably the toughest problem is that GemStone does not allow you to migrate instances that are on the _active_ stack ... after trying lots of different things, I finally settled on a technique where we used a forked thread to do the migrate for instances on the stack. While the forked code is active, the load stack is inactive and migration can occur ... 

You can take a look at the load method in the monticello package loader if you want to see  the level of hackery that has been employed:)
 
As a final comment ... if for some reason you mess up your class history, it should be possible to rebuild the class history from the instances of the old class ... while it is something you don't want to do ... it's worth keeping in mind that it can be done in an emergency:)


Ahhhh of course...the migrate stuff "just" changes the class pointer of the instances right? So if the slots for XXX instVars were there...they won't get lost. I guess it is similar to Pharo's #adoptInstance: and #primitiveChangeClassTo: 
Good!
 
Dale


On Wed, Apr 16, 2014 at 12:05 PM, Mariano Martinez Peck <[hidden email]> wrote:
Hi gemstoners,

I have just finished reading "Chapter 10 - Class Creation, Versions, and Instance Migration" but when I was about to start writing some scripts I found GsDeployer. I found this very interesting expression: "GsDeployer new doBulkMigrate".

I am not 100% sure of what it does, so please confirm if I understand correctly:

1) it searches each class of symbol list of current user that has more than 1 in the class history
2) it migrates each version of each found class to the last one from the history. And this migration is the basic ones... I mean, new instVars in new class will be with nil, and old instVars not existing in new class will be dropped, etc.
3) committs etc..

So...is that correct? If true, then it means that if I don't have any specific migration matter (like instVar renaming, or initialize some new instvar with some state that depends on old value, etc etc etc), that would migrate everything automatically, right?

But...if that's correct...I need to be very very very careful in executing such a migration since after the migration I will have lost all previous class versions and more importantly, I will have lost instVars from old classes in the case new class does not define them. Correct? 

Thanks in advance,

--
Mariano
http://marianopeck.wordpress.com

_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass





--
Mariano
http://marianopeck.wordpress.com


_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: [Glass] About GsDeployer new doBulkMigrate

James Foster-9
In reply to this post by Mariano Martinez Peck
> Ahhhh of course...the migrate stuff "just" changes the class pointer of the instances right? So if the slots for XXX instVars were there...they won't get lost. I guess it is similar to Pharo's #adoptInstance: and #primitiveChangeClassTo:

I don’t think so. Migration creates a completely new object in a different location, and offers the new object the chance to get data from the old object. By default, instance variables that are the same are copied across (you can override this method to do something else). After the new object copies whatever it wants, the system does a two-way become on the objects to swap the identities. (Because GemStone uses an object table, swapping identities is very easy.)

So, it does not “just” change the class pointer, it creates an entirely new object with different instance variables and the old object is immediately eligible for garbage collection (because no one else has a reference to it). If the new class does not have an instance variable XXX, then the slot for XXX is not present in the new object; the data in that slot in the old object will get lost.

My understanding is that this is essentially what all Smalltalks (including Pharo) do when you change the definition of a class: there is actually a new class and a scan is made through object memory finding instances of the old class, creating new instances of the new class, copying across instance variables that are shared, and making the old instances eligible for garbage collection. The difference with GemStone is that the migration is optional and the data copying can be controlled, while in other Smalltalks the migration is automatic and there is no opportunity to salvage data in instance variables that do not carry across. Thus, GemStone can have the same semantics as Pharo (except it takes longer if the object space is larger), but it can be more flexible.

While the old object is eligible for garbage collection, it is unlikely to be lost right away and can probably be found. I have had occasion to list instances of the old class (they are likely still around), and salvage things from them.

Does that make sense (or did you already understand all of this and I just misinterpreted you comment above!)?

James
_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: [Glass] About GsDeployer new doBulkMigrate

Mariano Martinez Peck



On Wed, Apr 16, 2014 at 9:40 PM, James Foster <[hidden email]> wrote:
> Ahhhh of course...the migrate stuff "just" changes the class pointer of the instances right? So if the slots for XXX instVars were there...they won't get lost. I guess it is similar to Pharo's #adoptInstance: and #primitiveChangeClassTo:

I don’t think so. Migration creates a completely new object in a different location, and offers the new object the chance to get data from the old object. By default, instance variables that are the same are copied across (you can override this method to do something else). After the new object copies whatever it wants, the system does a two-way become on the objects to swap the identities. (Because GemStone uses an object table, swapping identities is very easy.)

So, it does not “just” change the class pointer, it creates an entirely new object with different instance variables and the old object is immediately eligible for garbage collection (because no one else has a reference to it). If the new class does not have an instance variable XXX, then the slot for XXX is not present in the new object; the data in that slot in the old object will get lost.

My understanding is that this is essentially what all Smalltalks (including Pharo) do when you change the definition of a class: there is actually a new class and a scan is made through object memory finding instances of the old class, creating new instances of the new class, copying across instance variables that are shared, and making the old instances eligible for garbage collection. The difference with GemStone is that the migration is optional and the data copying can be controlled, while in other Smalltalks the migration is automatic and there is no opportunity to salvage data in instance variables that do not carry across. Thus, GemStone can have the same semantics as Pharo (except it takes longer if the object space is larger), but it can be more flexible.

While the old object is eligible for garbage collection, it is unlikely to be lost right away and can probably be found. I have had occasion to list instances of the old class (they are likely still around), and salvage things from them.

Does that make sense (or did you already understand all of this and I just misinterpreted you comment above!)?

Thanks James. Originally, I thought GemStone would do something like what you describe here. However, after Dale's comment it made me thing of a simply class pointer change. His comment that confused me is:   "if for some reason you mess up your class history, it should be possible to rebuild the class history from the instances of the old class"    
So....how that is possible? say old instances had a instVar XXX which new class doesn't have. Such slot will get lost when old instances are migrated. So...unless all old instances are still recheable, I will not be able to rebuild/recover my original old instances. Right? So Dale's comment is correct if only old instances are still recheable and not GCed ?

Thanks for the clarification. 


 

--
Mariano
http://marianopeck.wordpress.com

_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: [Glass] About GsDeployer new doBulkMigrate

James Foster-9
On Apr 16, 2014, at 5:56 PM, Mariano Martinez Peck <[hidden email]> wrote:




On Wed, Apr 16, 2014 at 9:40 PM, James Foster <[hidden email]> wrote:
> Ahhhh of course...the migrate stuff "just" changes the class pointer of the instances right? So if the slots for XXX instVars were there...they won't get lost. I guess it is similar to Pharo's #adoptInstance: and #primitiveChangeClassTo:

I don’t think so. Migration creates a completely new object in a different location, and offers the new object the chance to get data from the old object. By default, instance variables that are the same are copied across (you can override this method to do something else). After the new object copies whatever it wants, the system does a two-way become on the objects to swap the identities. (Because GemStone uses an object table, swapping identities is very easy.)

So, it does not “just” change the class pointer, it creates an entirely new object with different instance variables and the old object is immediately eligible for garbage collection (because no one else has a reference to it). If the new class does not have an instance variable XXX, then the slot for XXX is not present in the new object; the data in that slot in the old object will get lost.

My understanding is that this is essentially what all Smalltalks (including Pharo) do when you change the definition of a class: there is actually a new class and a scan is made through object memory finding instances of the old class, creating new instances of the new class, copying across instance variables that are shared, and making the old instances eligible for garbage collection. The difference with GemStone is that the migration is optional and the data copying can be controlled, while in other Smalltalks the migration is automatic and there is no opportunity to salvage data in instance variables that do not carry across. Thus, GemStone can have the same semantics as Pharo (except it takes longer if the object space is larger), but it can be more flexible.

While the old object is eligible for garbage collection, it is unlikely to be lost right away and can probably be found. I have had occasion to list instances of the old class (they are likely still around), and salvage things from them.

Does that make sense (or did you already understand all of this and I just misinterpreted you comment above!)?

Thanks James. Originally, I thought GemStone would do something like what you describe here. However, after Dale's comment it made me thing of a simply class pointer change. His comment that confused me is:   "if for some reason you mess up your class history, it should be possible to rebuild the class history from the instances of the old class"    
So....how that is possible? say old instances had a instVar XXX which new class doesn't have. Such slot will get lost when old instances are migrated. So...unless all old instances are still recheable, I will not be able to rebuild/recover my original old instances. Right? So Dale's comment is correct if only old instances are still recheable and not GCed ?

Thanks for the clarification. 

Dale’s comment is an accurate description of rebuilding a ClassHistory, while you are asking about recovering data from a migrated instance.

GemStone provides a way to group versions of a class into a ClassHistory, a subclass of Array. By default, when you create a new version of a class it gets added to the ClassHistory of the old version. If you do a lot of refactoring (and Smalltalkers should be doing this, right!?), then a ClassHistory can get large. If there is no reason to keep the old class versions, then you can remove a Class from a the ClassHistory. Sometimes I get a bit too aggressive in my housecleaning and discover that I prematurely removed something that I should have saved a bit longer, and thus I’ve “messed up my class history.” (Actually, Dale might have had me in mind when he said this. He knows, and teases me periodically, about my habit of deleting things that I think I won’t need. I periodically have to go to him and ask him to resend an email that I prematurely deleted!)

So, to rebuild a ClassHistory, you find the classes, add them to a new ClassHistory, and then add the ClassHistory to the class. How do you find the classes? if you haven’t migrated all the instances, then when you stumble across an old instance you can ask it for its class. If it doesn’t share a ClassHistory with the class you want to migrate to, then you probably have to “rebuild the class history” (as Dale suggests).

If you no longer have a reference to an old instance, but believe it is still out there (not yet garbage collected), then you can find the instances of a class by using the #’allInstances’ method on the old Class. If you don’t have a reference to the old Class you can try #’allInstances’ on Metaclass3. 

So, Dale was talking about rebuilding a ClassHistory, which can be done (I’ve done it many times). As to your question about old instances, as long as they are not GCed, then you can still get them using the #’allInstances’ methods discussed above.

James


_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: [Glass] About GsDeployer new doBulkMigrate

Martin McClure-5
In reply to this post by Mariano Martinez Peck
On 04/16/2014 04:31 PM, Mariano Martinez Peck wrote:

>     As a final comment ... if for some reason you mess up your class
>     history, it should be possible to rebuild the class history from the
>     instances of the old class ... while it is something you don't want
>     to do ... it's worth keeping in mind that it can be done in an
>     emergency:)
>
>
> Ahhhh of course...the migrate stuff "just" changes the class pointer of
> the instances right? So if the slots for XXX instVars were there...they
> won't get lost. I guess it is similar to Pharo's #adoptInstance: and
> #primitiveChangeClassTo:
> Good!

No, I think Dale's comment only applies to recovering classes that have
been removed from the class history, not to recovering lost values from
instances due to instvar removal.

Migration of an instance creates a new instance of the new version of
the class, copies instvar values across, then uses #become: to swap
identities of the old and new instances. So if an instvar has been
removed or renamed in the new class version, you *can* lose data with a
default migration. There are ways to customize migration, but I don't
know how those interact with GsDeployer.

Regards,

-Martin
_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass
Reply | Threaded
Open this post in threaded view
|

Re: [Glass] About GsDeployer new doBulkMigrate

Dale Henrichs-3
Sorry for the confusion, but as Martin and James have pointed out, I was only talking about rebuilding class history:)

It's always possible to make mistakes, so the best course of action is to use a sand box repository (backup copy of production running in a stone completely isolated from production) where you test and fine tune all code update scripts in a completely safe environment. 

It always pays to be paranoid when making changes in your production repository:)

Dale


On Wed, Apr 16, 2014 at 8:05 PM, Martin McClure <[hidden email]> wrote:
On 04/16/2014 04:31 PM, Mariano Martinez Peck wrote:
    As a final comment ... if for some reason you mess up your class
    history, it should be possible to rebuild the class history from the
    instances of the old class ... while it is something you don't want
    to do ... it's worth keeping in mind that it can be done in an
    emergency:)


Ahhhh of course...the migrate stuff "just" changes the class pointer of
the instances right? So if the slots for XXX instVars were there...they
won't get lost. I guess it is similar to Pharo's #adoptInstance: and
#primitiveChangeClassTo:
Good!

No, I think Dale's comment only applies to recovering classes that have been removed from the class history, not to recovering lost values from instances due to instvar removal.

Migration of an instance creates a new instance of the new version of the class, copies instvar values across, then uses #become: to swap identities of the old and new instances. So if an instvar has been removed or renamed in the new class version, you *can* lose data with a default migration. There are ways to customize migration, but I don't know how those interact with GsDeployer.

Regards,

-Martin


_______________________________________________
Glass mailing list
[hidden email]
http://lists.gemtalksystems.com/mailman/listinfo/glass