LCOV - code coverage report
Current view: top level - sql/storage - store_sequence.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 132 158 83.5 %
Date: 2024-12-19 23:10:26 Functions: 13 13 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "store_sequence.h"
      15             : #include "sql_storage.h"
      16             : 
      17             : void
      18        1808 : sequences_lock(sql_store Store)
      19             : {
      20        1808 :         sqlstore *store = Store;
      21        1808 :         MT_lock_set(&store->column_locks[NR_COLUMN_LOCKS-1]);
      22        1808 : }
      23             : 
      24             : void
      25        1808 : sequences_unlock(sql_store Store)
      26             : {
      27        1808 :         sqlstore *store = Store;
      28        1808 :         MT_lock_unset(&store->column_locks[NR_COLUMN_LOCKS-1]);
      29        1808 : }
      30             : 
      31             : typedef struct store_sequence {
      32             :         sqlid seqid;
      33             :         lng cur;
      34             :         bool intrans;
      35             : } store_sequence;
      36             : 
      37             : void
      38         766 : log_store_sequence(sql_store Store, void *s)
      39             : {
      40         766 :         sqlstore *store = Store;
      41         766 :         store_sequence *seq = s;
      42         766 :         store->logger_api.log_tsequence(store, seq->seqid,  seq->cur);
      43         766 :         seq->intrans = false;
      44         766 : }
      45             : 
      46             : int
      47         175 : seq_hash(void *s)
      48             : {
      49         175 :         store_sequence *seq = s;
      50         175 :         return seq->seqid;
      51             : }
      52             : 
      53             : static void
      54         175 : sequence_destroy( void *dummy, store_sequence *s )
      55             : {
      56         175 :         (void)dummy;
      57         175 :         _DELETE(s);
      58         175 : }
      59             : 
      60             : void
      61         351 : seq_hash_destroy( sql_hash *h )
      62             : {
      63         351 :         if (h == NULL || h->sa)
      64             :                 return ;
      65       11550 :         for (int i = 0; i < h->size; i++) {
      66       11200 :                 sql_hash_e *e = h->buckets[i];
      67             : 
      68       11375 :                 while (e) {
      69         175 :                         sql_hash_e *next = e->chain;
      70             : 
      71         175 :                         sequence_destroy(NULL, e->value);
      72         175 :                         _DELETE(e);
      73         175 :                         e = next;
      74             :                 }
      75             :         }
      76         350 :         _DELETE(h->buckets);
      77         350 :         _DELETE(h);
      78             : }
      79             : 
      80             : static store_sequence *
      81        1177 : sequence_lookup( sql_hash *h, sqlid id)
      82             : {
      83        1177 :         sql_hash_e *e = h->buckets[id & (h->size-1)];
      84        1184 :         while(e) {
      85         971 :                 sql_hash_e *next = e->chain;
      86         971 :                 store_sequence *s = e->value;
      87             : 
      88         971 :                 if (s->seqid == id)
      89         964 :                         return s;
      90             :                 e = next;
      91             :         }
      92             :         return NULL;
      93             : }
      94             : 
      95             : /* lock is held */
      96             : static store_sequence *
      97        1072 : update_sequence(sqlstore *store, store_sequence *s)
      98             : {
      99        1072 :         if (!s->intrans && !list_append(store->seqchanges, s))
     100             :                 return NULL;
     101        1072 :         s->intrans = true;
     102        1072 :         return s;
     103             : }
     104             : 
     105             : /* lock is held */
     106             : static store_sequence *
     107         175 : sequence_create(sqlstore *store, sql_sequence *seq )
     108             : {
     109         175 :         lng val = 0;
     110         175 :         store_sequence *s = NULL;
     111         175 :         s = MNEW(store_sequence);
     112         175 :         if(!s)
     113             :                 return NULL;
     114             : 
     115         175 :         *s = (store_sequence) {
     116         175 :                 .seqid = seq->base.id,
     117         175 :                 .cur = seq->start,
     118             :         };
     119             : 
     120         175 :         if (!isNew(seq) && store->logger_api.get_sequence(store, seq->base.id, &val ))
     121          13 :                 s->cur = val;
     122         175 :         if (!hash_add(store->sequences, seq_hash(s), s)) {
     123           0 :                 _DELETE(s);
     124           0 :                 return NULL;
     125             :         }
     126             :         return s;
     127             : }
     128             : 
     129             : int
     130          47 : seq_restart(sql_store Store, sql_sequence *seq, lng start)
     131             : {
     132          47 :         store_sequence *s;
     133          47 :         sqlstore *store = Store;
     134             : 
     135          47 :         assert(!is_lng_nil(start));
     136          47 :         sequences_lock(store);
     137          47 :         s = sequence_lookup(store->sequences, seq->base.id);
     138             : 
     139          47 :         if (!s) {
     140          38 :                 lng val = 0;
     141             : 
     142          38 :                 if (isNew(seq) || !store->logger_api.get_sequence(store, seq->base.id, &val )) {
     143          38 :                         sequences_unlock(store);
     144          38 :                         return 1;
     145             :                 } else {
     146           0 :                         s = sequence_create(store, seq);
     147           0 :                         if (!s) {
     148           0 :                                 sequences_unlock(store);
     149           0 :                                 return 0;
     150             :                         }
     151             :                 }
     152             :         }
     153           9 :         lng ocur = s->cur;
     154           9 :         s->cur = start;
     155           9 :         if (!update_sequence(store, s)) {
     156           0 :                 s->cur = ocur;
     157           0 :                 sequences_unlock(store);
     158           0 :                 return 0;
     159             :         }
     160           9 :         sequences_unlock(store);
     161           9 :         return 1;
     162             : }
     163             : 
     164             : int
     165        1064 : seqbulk_next_value(sql_store Store, sql_sequence *seq, lng cnt, lng* dest)
     166             : {
     167        1064 :         store_sequence *s;
     168        1064 :         sqlstore *store = Store;
     169             : 
     170             :         // either dest is an array of size cnt or dest is a normal pointer and cnt == 1.
     171             : 
     172        1064 :         assert(dest);
     173             : 
     174        1064 :         sequences_lock(store);
     175        1064 :         s = sequence_lookup(store->sequences, seq->base.id);
     176        1064 :         if (!s) {
     177         136 :                 s = sequence_create(store, seq);
     178         136 :                 if (!s) {
     179           0 :                         sequences_unlock(store);
     180           0 :                         return 0;
     181             :                 }
     182             :         }
     183             : 
     184        1064 :         lng min = seq->minvalue;
     185        1064 :         lng max = seq->maxvalue;
     186        1064 :         lng cur = s->cur;
     187             : 
     188        1064 :         if (!seq->cycle) {
     189        1046 :                 if ((seq->increment > 0 && s->cur > max) ||
     190          16 :                     (seq->increment < 0 && s->cur < min)) {
     191           1 :                         sequences_unlock(store);
     192           1 :                         return 0;
     193             :                 }
     194             :         }
     195        1063 :         bool store_unlocked = false;
     196        1063 :         if (seq->increment > 0) {
     197        1046 :                 lng inc = seq->increment; // new value = old value + inc;
     198             : 
     199        1046 :                 if (0 < cnt && !seq->cycle && !(max > 0 && s->cur < 0)) {
     200        1028 :                         if ((max - s->cur) >= ((cnt-1) * inc)) {
     201        1028 :                                 lng ocur = s->cur;
     202        1028 :                                 s->cur += inc * cnt;
     203             : 
     204        1028 :                                 if (!update_sequence(store, s)) {
     205           0 :                                         s->cur = ocur;
     206           0 :                                         sequences_unlock(store);
     207           0 :                                         return 0;
     208             :                                 }
     209        1028 :                                 sequences_unlock(store);
     210        1028 :                                 store_unlocked = true;
     211             :                         } else {
     212           0 :                                 sequences_unlock(store);
     213           0 :                                 return 0;
     214             :                         }
     215             :                 }
     216     2031435 :                 for(lng i = 0; i < cnt; i++) {
     217     2030389 :                         dest[i] = cur;
     218     2030389 :                         if ((GDK_lng_max - inc < cur) || ((cur += inc) > max)) {
     219             :                                 // overflow
     220           7 :                                 cur = (seq->cycle)?min:lng_nil;
     221             :                         }
     222             :                 }
     223             :         } else { // seq->increment < 0
     224          17 :                 lng inc = -seq->increment; // new value = old value - inc;
     225             : 
     226          17 :                 if (0 < cnt && !seq->cycle && !(min < 0 && s->cur > 0)) {
     227          15 :                         if ((s->cur - min) >= ((cnt-1) * inc)) {
     228          15 :                                 lng ocur = s->cur;
     229          15 :                                 s->cur -= inc * cnt;
     230             : 
     231          15 :                                 if (!update_sequence(store, s)) {
     232           0 :                                         s->cur = ocur;
     233           0 :                                         sequences_unlock(store);
     234           0 :                                         return 0;
     235             :                                 }
     236          15 :                                 sequences_unlock(store);
     237          15 :                                 store_unlocked = true;
     238             :                         } else {
     239           0 :                                 sequences_unlock(store);
     240           0 :                                 return 0;
     241             :                         }
     242             :                 }
     243          70 :                 for(lng i = 0; i < cnt; i++) {
     244          53 :                         dest[i] = cur;
     245          53 :                         if ((-GDK_lng_max + inc > cur) || ((cur -= inc)  < min)) {
     246             :                                 // underflow
     247           3 :                                 cur = (seq->cycle)?max:lng_nil;
     248             :                         }
     249             :                 }
     250             :         }
     251             : 
     252        1063 :         if (!store_unlocked) {
     253          20 :                 lng ocur = s->cur;
     254          20 :                 s->cur = cur;
     255             : 
     256          20 :                 if (!update_sequence(store, s)) {
     257           0 :                         s->cur = ocur;
     258           0 :                         sequences_unlock(store);
     259           0 :                         return 0;
     260             :                 }
     261          20 :                 sequences_unlock(store);
     262             :         }
     263             :         return 1;
     264             : }
     265             : 
     266             : int
     267         974 : seq_next_value(sql_store store, sql_sequence *seq, lng *val)
     268             : {
     269         974 :         return seqbulk_next_value(store, seq, 1, val);
     270             : }
     271             : 
     272             : int
     273          66 : seq_get_value(sql_store Store, sql_sequence *seq, lng *val)
     274             : {
     275          66 :         store_sequence *s;
     276          66 :         sqlstore *store = Store;
     277             : 
     278          66 :         *val = 0;
     279          66 :         sequences_lock(store);
     280          66 :         s = sequence_lookup(store->sequences, seq->base.id);
     281          66 :         if (!s) {
     282          39 :                 s = sequence_create(store, seq);
     283          39 :                 if (!s) {
     284           0 :                         sequences_unlock(store);
     285           0 :                         return 0;
     286             :                 }
     287             :         }
     288          66 :         *val = s->cur;
     289          66 :         sequences_unlock(store);
     290          66 :         return 1;
     291             : }

Generated by: LCOV version 1.14