Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PostgreSql membership tests #2113

Merged
merged 13 commits into from
Sep 19, 2016
Merged

PostgreSql membership tests #2113

merged 13 commits into from
Sep 19, 2016

Conversation

xclayl
Copy link
Contributor

@xclayl xclayl commented Sep 4, 2016

I don't expect this to be accepted yet -- personally, I'd like to get the Reminders and Stats tests working first.

This pull request is to give people heads-up that I'm working in this area and to get feedback on the work so far.

Cheers,
Clay

Update 2016-09-12 This PR is ready to be merged. It includes Reminders and Stats now (as well as Membership). It does not include blob storage. And it does not include changes to the documentation.

@dnfclas
Copy link

dnfclas commented Sep 4, 2016

Hi @xclayl, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution!

In order for us to evaluate and accept your PR, we ask that you sign a contribution license agreement. It's all electronic and will take just minutes. I promise there's no faxing. https://cla2.dotnetfoundation.org.

TTYL, DNFBOT;

@dnfclas
Copy link

dnfclas commented Sep 4, 2016

@xclayl, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR.

Thanks, DNFBOT;



-- For each deployment, there will be only one (active) membership version table version column which will be updated periodically.
CREATE TABLE IF NOT EXISTS OrleansMembershipVersionTable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be OK while scripting by yourself, but it might be easier to take the script and add it to some tooling (Red Gate etc.), if it were just a simple CREATE TABLE. My impression, but I don't have wide experience with all kinds of tooling.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been convenient while running/debugging. If there is a change to a query, I can run the whole script and it doesn't error.
I'd be interesting in knowing what the plan is when SQL changes are needed (added SiloName column for instance). How do we help users upgrade their database?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've wondered if I could update the script to drop the tables. That way people could run the script to update their database. How would a running cluster of Orleans silos react if all the data in the tables were wiped out?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be interesting in knowing what the plan is when SQL changes are needed (added SiloName column for instance). How do we help users upgrade their database?

The changes are usually backwards compatible. When we have to make changes to the schema, which is very rare, we note it in the release notes. Thus far, we haven't made upgrade scripts.

I've wondered if I could update the script to drop the tables. That way people could run the script to update their database. How would a running cluster of Orleans silos react if all the data in the tables were wiped out?

I suggest you keep the semantics of the other scripts. Orleans membership will fail in case the table is wiped. Also, I wouldn't want people to mistakenly lose all their reminders data.

@veikkoeeva
Copy link
Contributor

@xclayl Looks like you're in good swing. I basically scrolled it through in minute, so this isn't that exhaustive. One thing you don't know, we tried to align the SQL Server and MySQL scripts closer together so they'd be easier to compare when making changes and fixes, with regard to this importan PR, it'd mean filling the query table what looks like to me like in MySQL.

@veikkoeeva
Copy link
Contributor

If you hit a roadblock and run out of minutes in the day, don't hesitate to ping on Gitter someone or here me or @shayhatsor.

@veikkoeeva
Copy link
Contributor

@xclayl Also, the stats systems should be overhauled completely to provide numeric values and decompound the compound values. It's on my mental todo list, but I'm thin on time and I've waited for the telemetry story to finish. In case you have time and ideas, don't keep them buried but pop by on Gitter or open an issue (or maybe I should open an issue about it).

@xclayl
Copy link
Contributor Author

xclayl commented Sep 4, 2016

@veikkoeeva thanks for the quick response. I'm happy to help with PostgreSQL changes related to the stats, but I would be unlikely to spearhead that change. There's a project I want to work on that uses Orleans, and that is my main focus.

it'd mean filling the query table what looks like to me like in MySQL

I'm not sure what you mean here. I suspect you're saying that the pgsql code shouldn't use functions, and I'd like that too, however I don't know a way to do all that was needed (transactions, SELECTing 1 or 0, etc) in pgsql without functions. It'd make me happy for someone to prove me wrong and rewrite it without functions. I'm always happy to learn new things.
Thanks for the offer to help on Gitter. It was a large learning curve with the test framework and a quick answer to a question would make it easier.

options.ClusterConfiguration.Globals.AdoInvariant = AdoNetInvariants.InvariantNamePostgreSql;
options.ClusterConfiguration.PrimaryNode = null;
options.ClusterConfiguration.Globals.SeedNodes.Clear();
options.ClientConfiguration.AdoInvariant = AdoNetInvariants.InvariantNamePostgreSql;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can now remove this line, since I fixed the TestClusterOptions in #2116

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shayhatsor thanks for that -- done

@veikkoeeva
Copy link
Contributor

@xclayl

I'm not sure what you mean here. I suspect you're saying that the pgsql code shouldn't use functions, and I'd like that too, however I don't know a way to do all that was needed (transactions, SELECTing 1 or 0, etc) in pgsql without functions. It'd make me happy for someone to prove me wrong and rewrite it without functions. I'm always happy to learn new things.
Thanks for the offer to help on Gitter. It was a large learning curve with the test framework and a quick answer to a question would make it easier.

Not at all, do use functions if it makes sense. Even the SQL Serve one could benefit of it if the queries would be compiled to native queries. Though that's not something everyone is willing to pay for in licences. :)

Anyway, it looked to me they were spread out differently than in the MySQL case, so I wanted to just point out there's some value having them more aligned. It's easier to make changes and check them side-by-side then. I could be wrong with this, ignore in that case.

It's great you're doing this. It's naturally entirely OK not to break youreself labouring here. It's good sometimes to air out ideas so that as many people as possible know potential plans. :)

@xclayl
Copy link
Contributor Author

xclayl commented Sep 7, 2016

@veikkoeeva I want to box this off and move on to the next part (of my project) -- on to Angular2, TypeScript and Material Design. I'll be around though to support Orleans/PostgreSql. Are you able to contact me via GitHub?

That last piece for Orleans/PostgreSql is the storage framework, which I don't plan to use. I get nervous (that's not quite the right word) about coding something I don't have a vested interest in, but let's box off PostgreSql.

How does the process work now on? Should I create a new pull request? It looks like this pull request is tracking my master branch, cool. I'm new to git and GitHub, so please let me know if you want something done differently.

@xclayl
Copy link
Contributor Author

xclayl commented Sep 7, 2016

@veikkoeeva After reviewing the PostgreSql and MySql scripts, the "INSERT INTO OrleansQuery" statements are in the same order. However, the functions are created in different places. The difference is the MySql script creates all the functions after "InsertMembershipKey". The PostgreSql script creates each function right before the related "INSERT INTO OrleansQuery" statement. PostgreSql script seems more organised to me, but I'm happy to follow MySql if that is preferred.

@veikkoeeva
Copy link
Contributor

@xclayl I think it's OK to leave the storage stuff out. Maybe we should split it to a separate script too.

Yeah, have a pull request and people pour over it. Probably me and @shayhatsor and some of the core team members. If the tests pass, it's a good sign.

I don't know your contact details and I don't know if you see mine, but if by contacting you mean pinging in some way, I get a message every time you refer to me somewhere. And I'm on plenty of channels too in Gitter, in Orleans for instance too.

It's just right now I'm sluggish as we have a big push to production at work and I have other non-work relateted commitments. Prioritizing etc. :)

@shayhatsor
Copy link
Member

@xclayl & @veikkoeeva , do you consider this work ready for merge?

@xclayl
Copy link
Contributor Author

xclayl commented Sep 8, 2016

@shayhatsor The work isn't done quite yet. I'd like to tidy up some stray code and add documenation so that users know how to setup the Npgsql provider.

@xclayl
Copy link
Contributor Author

xclayl commented Sep 11, 2016

@shayhatsor The work here is done. I see the documentation in another branch, so that will have to be another PR.
Thanks @shayhatsor and @veikkoeeva for your help.

@@ -192,14 +192,18 @@ internal static ReminderEntry GetReminderEntry(IDataRecord record)
/// </summary>
private static string TryGetSiloName(IDataRecord record)
{
for (var i = 0; i < record.FieldCount; ++i)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this change is necessary, I'd rather we don't use an exception

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was erroring since the method was looking for the column in case sensitive way. I changed it to use GetOrdinal() so that SiloName worked the same way as the other columns which use GetOrdinal() under the covers. GetOrdinal() first does a case-sensitive search and if the column isn't found, it does a case-insensitive search. One option is to duplicate this behavior so that it doesn't throw exceptions.
Another option is to return the columns with the upper-lower case originally expected. But just out of curiosity, why does this column work differently than the others? ie "TryGet..."

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I personally have no problem with it looking for the column in case sensitive way. But I'm OK with your change. This column is different because we've (re)added it and wanted to keep the code backwards compatible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xclayl In addition, there's always room for improvements. If you notice something and aren't in a hurry, just a make a mental note and drop it to a chat or open an issue and someone and eventually things improve. :)

I think I have have some time tomorrow to take a deeper look at this, but I need to upgrade my VM with PostregreSQL so realistically I drop comments, if there's any – looks good at a glance – on Wednesday or Thursday. If there's hurry to get into the 1.3.0 time window I can go to sleep a bit later. :) @jdom? @sergeybykov? Still time?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xclayl A tangential that might make sense (but can also be refactored in another PR if it makes sense)

Another option is to return the columns with the upper-lower case originally expected. But just out of curiosity, why does this column work differently than the others? ie "TryGet..."

/// <summary>
        /// Returns a value if it is not <see cref="System.DBNull"/>, <em>default(TValue)</em> otherwise.
        /// </summary>
        /// <typeparam name="TValue">The type of the value to request.</typeparam>
        /// <param name="record">The record from which to retrieve the value.</param>
        /// <param name="fieldName">The name of the field to retrieve.</param>
        /// <param name="default">The default value if value in position is <see cref="System.DBNull"/>.</param>
        /// <returns>Either the given value or the default for the requested type.</returns>
        /// <exception cref="IndexOutOfRangeException"/>
        /// <remarks>This function throws if the given <see paramref="fieldName"/> does not exist.</remarks>
        public static TValue GetValueOrDefault<TValue>(this IDataRecord record, string fieldName, TValue @default = default(TValue))
        {
            var ordinal = record.GetOrdinal(fieldName);
            return record.IsDBNull(ordinal) ? @default : (TValue)record.GetValue(ordinal);
}

https://github.com/dotnet/orleans/blob/master/src/OrleansSQLUtils/Storage/DbExtensions.cs#L117

Or

`/// <summary>
        /// Returns a value with the given <see paramref="fieldName"/>.
        /// </summary>
        /// <typeparam name="TValue">The type of value to retrieve.</typeparam>
        /// <param name="record">The record from which to retrieve the value.</param>
        /// <param name="fieldName">The name of the field.</param>
        /// <returns>Value in the given field indicated by <see paramref="fieldName"/>.</returns>
        /// <exception cref="IndexOutOfRangeException"/>
        /// <remarks>This function throws if the given <see paramref="fieldName"/> does not exist.</remarks>        
        public static TValue GetValue<TValue>(this IDataRecord record, string fieldName)
        {
            var ordinal = record.GetOrdinal(fieldName);
            return (TValue)record.GetValue(ordinal);
}

https://github.com/dotnet/orleans/blob/master/src/OrleansSQLUtils/Storage/DbExtensions.cs#L180

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These won't work, b/c the column may not be SELECTed at all.

@veikkoeeva
Copy link
Contributor

veikkoeeva commented Sep 11, 2016

@xclayl I'll take a look in the coming days. A first note is that you're still checking the existence of objects before creating them. The other two scripts don't do that. I suggest we do as currently in the othet two and if warranted, open an issue for discussion if the scripts should fail in case objects already exist or carry on execution. /cc @shayhatsor

@xclayl
Copy link
Contributor Author

xclayl commented Sep 11, 2016

@veikkoeeva There isn't much difference between the two (both types of scripts expect the database to be empty), so I'm not bothered about taking out the "if exists". I might be interested in a discussion about upgrading databases, but what I've done isn't the whole answer, so I'll change the script to be more like the others.

@xclayl
Copy link
Contributor Author

xclayl commented Sep 12, 2016

@veikkoeeva Script cleaned up. I'd like to do what I can to include this in 1.3. The only outstanding issue I know of is documentation, but that would be in a different PR.

@veikkoeeva
Copy link
Contributor

@xclayl Check! I wrote in Gitter the the tests are green, though I had slight trouble https://gitter.im/dotnet/orleans?at=57d9bfebc3e7045a304d8ebe. I'll try to follow tomorrow and see if it's a wrap as far as I can think of anything. :)

Copy link
Contributor

@veikkoeeva veikkoeeva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is easty to overlook, remember also to update the Nuget package on include the PostgreSql script. This way it's delivered together with the binaries and it can be retrieved from the Nuget directory.

new StorageConnection
{
StorageInvariant = AdoNetInvariants.InvariantNamePostgreSql,
ConnectionString = "Server=127.0.0.1;Port=5432;Database=postgres;Integrated Security=true;Pooling=false;"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xclayl It looks like safest to remove the pooling feature. As you rightfuly pointed out, including this (without pgbouncer etc.) gives easily exceptions.

{
setupScript,
CreateStreamTestTable
}; // setupScript.Split(new[] { "GO" }, StringSplitOptions.RemoveEmptyEntries).ToList();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These extraneous comments could be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks - I want this tidy too.


public override string DefaultConnectionString
{
get { return @"Server=127.0.0.1;Port=5432;Database=postgres;Integrated Security=true;Pooling=false;"; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xclayl It looks like safest to remove the pooling feature. As you rightfuly pointed out, including this (without pgbouncer etc.) gives easily exceptions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@veikkoeeva, I believe I have this set to the most reliable way now -- I kept pooling off and restored the code that kills sessions when dropping the database.

WHERE
ServiceId = @ServiceId AND @ServiceId IS NOT NULL;
');

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spurious empty lines.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty lines removed at the end of file (WHERE clause not changed). I think that's what you mean.



CREATE FUNCTION update_i_am_alive_time(
deployment_id OrleansMembershipTable.DeploymentId%TYPE,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is creative. 👍

PeriodArg,
GrainHashArg,
0
ON CONFLICT (ServiceId, GrainId, ReminderName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, the new PostgreSQL "UPSERT" syntax, I assume (I'm a PostgreSQL n00b). 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes -- the upsert statement is highly consistent too -- two statements running at the same time will never error -- unlike TSQL's Merge statement. But then again, TSQL's Merge has more features.


CONSTRAINT PK_OrleansMembershipVersionTable_DeploymentId PRIMARY KEY(DeploymentId)
);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a minor nit that doesn't extract value from this contribution, but the empty lines between the constructs vary. They could be normalized (two empty lines?).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what is the issue here. The empty lines around the CONSTRAINTs looks the same throughout the file and the same to SQL Server's script. I'm pretty sure I didn't touch these lines since they match TSQL.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I think you mean between the statements. I'll tidy it up...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty lines removed

@veikkoeeva
Copy link
Contributor

veikkoeeva commented Sep 15, 2016

@xclayl Easy to overlook, remember to update the Nuget file to include the PostgreSQL script. This way it can be retrieved from the Nuget folder along with the binaries.

@veikkoeeva
Copy link
Contributor

@shayhatsor Do you see anything? Otherwise than the minor comments this looks good to me! 👍

@shayhatsor
Copy link
Member

LGTM, after @xclayl makes the changes @veikkoeeva has mentioned, I'll merge.

@veikkoeeva veikkoeeva mentioned this pull request Sep 17, 2016
2 tasks
@xclayl
Copy link
Contributor Author

xclayl commented Sep 17, 2016

@veikkoeeva, nuget file updated. I tried to test it by building it, but I couldn't figure it out. If you know how, can you test it?

@shayhatsor
Copy link
Member

@xclayl , to test the build locally, including nuget package generation, run build.cmd

@xclayl
Copy link
Contributor Author

xclayl commented Sep 17, 2016

@shayhatsor thanks I'll test it out :)

@xclayl
Copy link
Contributor Author

xclayl commented Sep 17, 2016

built nuget package and I can see the sql script inside the nuget package.

@shayhatsor & @veikkoeeva, I believe I have done all the outstanding issues. Let me know if I've left anything off or not done it in a way you meant.

Cheers,
Clay

@shayhatsor shayhatsor merged commit bebdd80 into dotnet:master Sep 19, 2016
@shayhatsor
Copy link
Member

@xclayl, thank you for the contribution!

@sergeybykov
Copy link
Contributor

@xclayl, this is great! Thank you!

@xclayl
Copy link
Contributor Author

xclayl commented Sep 19, 2016

I want to thank you all in particular for being so welcoming to contributions.

@github-actions github-actions bot locked and limited conversation to collaborators Dec 9, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants