<commit_before>/*
* File:  updates.cpp
* Copyright (C) 2004 The Institute for System Programming of the Russian Academy of Sciences (ISP RAS)
*/

#include "common/sedna.h"

#include "tr/updates/updates.h"
#include "tr/mo/mo.h"
#include "tr/crmutils/node_utils.h"
#include "tr/executor/base/xptr_sequence.h"
#include "tr/nid/numb_scheme.h"
#include "tr/executor/xqops/PPConstructors.h"
#include "tr/mo/indirection.h"

#ifdef SE_ENABLE_TRIGGERS
#include "tr/triggers/triggers.h"
#endif

#define IGNORE_UPDATE_ERRORS

#ifdef SE_ENABLE_FTSEARCH
std::map<ft_index_cell_xptr,update_history*> ft_updates;
#endif

#ifdef SE_ENABLE_FTSEARCH
void clear_ft_sequences()
{
    std::map<ft_index_cell_xptr,update_history*>::iterator it=ft_updates.begin();
    while (it!=ft_updates.end())
    {
        delete it->second;
        it++;
    }
    ft_updates.clear();
}
void execute_modifications()
{
    if (indirectionGetRollbackMode()) return;
    std::map<ft_index_cell_xptr,update_history*>::iterator it=ft_updates.begin();
    while (it!=ft_updates.end())
    {
        it->first->update_index(it->second);
        it++;
    }
}
void update_insert_sequence(xptr node,ft_index_cell_cptr icell)
{
    std::map<ft_index_cell_xptr,update_history*>::iterator it=ft_updates.find(icell.ptr());
    if (it==ft_updates.end())
    {
        update_history *h=se_new update_history();
		h->add_insert_node(node);
        ft_updates[icell.ptr()]=h;
    }
    else
        it->second->add_insert_node(node);

}
void update_update_sequence(xptr node,ft_index_cell_cptr icell)
{
    std::map<ft_index_cell_xptr,update_history*>::iterator it=ft_updates.find(icell.ptr());
    if (it==ft_updates.end())
    {
        update_history *h=se_new update_history();
        h->add_update_node(node);
        ft_updates[icell.ptr()]=h;
    }
    else
        it->second->add_update_node(node);
}
void update_delete_sequence(xptr node,ft_index_cell_cptr icell)
{
    std::map<ft_index_cell_xptr,update_history*>::iterator it=ft_updates.find(icell.ptr());
    if (it==ft_updates.end())
    {
        update_history* h=se_new update_history();
        h->add_delete_node(node);
        ft_updates[icell.ptr()]=h;
    }
    else
        it->second->add_delete_node(node);
}

void update_insert_sequence(xptr node,schema_node_cptr icell)
{
    cat_list<ft_index_cell_xptr>::item* obj=icell->ft_index_list.first;
    if (obj == NULL) return;
    CHECKP(node);
    xptr ind=((n_dsc*)XADDR(node))->indir;
    while (obj!=NULL)
    {
        update_insert_sequence(ind,ft_index_cell_cptr(obj->object));
        obj=obj->next;
    }
    CHECKP(node);
}

void update_update_sequence(xptr node,schema_node_cptr icell)
{
    cat_list<ft_index_cell_xptr>::item* obj=icell->ft_index_list.first;
    if (obj==NULL) return;
    CHECKP(node);
    xptr ind=((n_dsc*)XADDR(node))->indir;
    while (obj!=NULL)
    {
        update_update_sequence(ind,ft_index_cell_cptr(obj->object));
        obj=obj->next;
    }
    CHECKP(node);
}

void update_delete_sequence(xptr node,schema_node_cptr icell)
{
    cat_list<ft_index_cell_xptr>::item* obj=icell->ft_index_list.first;
    if (obj==NULL) return;
    CHECKP(node);
    xptr ind=((n_dsc*)XADDR(node))->indir;
    while (obj!=NULL)
    {
        update_delete_sequence(ind,ft_index_cell_cptr(obj->object));
        obj=obj->next;
    }
    CHECKP(node);
}

void init_ft_sequences (const xptr& left, const xptr& right, const xptr& parent)
{
    if (IS_TMP_BLOCK(left)||IS_TMP_BLOCK(right)||IS_TMP_BLOCK(parent)) return;
    xptr tmp;
    schema_node_cptr scn = XNULL;
    if (parent!=XNULL)
    {
        tmp=parent;
        CHECKP(parent);
        scn=(GETBLOCKBYNODE(parent))->snode;
    }
    else
    {
        tmp=(left==XNULL)?right:left;
        CHECKP(tmp);
        scn=(GETBLOCKBYNODE(tmp))->snode->parent;
    }

    if (scn->root == scn.ptr() || scn->root->full_ft_index_list.empty()) return;

    while (scn.found())
    {
        cat_list<ft_index_cell_xptr>::item* obj=scn->ft_index_list.first;
        if (obj!=NULL)
        {
            tmp=getNodeAncestorIndirectionByScheme(tmp,scn);
            while (obj!=NULL)
            {
                update_update_sequence(tmp,ft_index_cell_cptr(obj->object));
                obj=obj->next;
            }
            tmp=removeIndirection(tmp);
        }
        scn=scn->parent;
    }
}
#endif

xptr copy_node_content(xptr new_node_i, xptr node, xptr left_node_i, upd_ns_map** nsupdmap, bool save_types, unsigned short depth) {
    xptr left_node = XNULL;
    xptr childi = getIndirectionSafeCP(getFirstByOrderChildCP(node));

    while (childi != XNULL) {
        left_node = deep_copy_node_i(left_node_i, XNULL, new_node_i, indirectionDereferenceCP(childi), nsupdmap, save_types, depth + 1);

        /* due to : MG: deep_temp_copy can return XNULL if a trigger canceled
        * the insertion and there were now any left sibling */
        if (left_node != XNULL) {
            left_node_i = getIndirectionSafeCP(left_node);
        }

        childi = getRightSiblingIndirectionCP(indirectionDereferenceCP(childi));
    }

    return left_node_i;
}

void swizzleNamespace (xmlns_ptr & ns, upd_ns_map*& updmap)
{
    if (updmap == NULL) updmap = se_new upd_ns_map;
    upd_ns_map::const_iterator it = updmap->find(ns);
    if (it == updmap->end()) {
        ns = xmlns_touch(ns->prefix, ns->uri);
    } else {
        ns = it->second;
    }
}

xptr deep_copy_node(xptr left, xptr right, xptr parent, xptr node, upd_ns_map** nsupdmap, bool save_types, unsigned short depth)
{
    xptr result;
    xptr node_indir;
    schema_node_cptr scmnode;
    xmlscm_type scm_type;

#ifdef SE_ENABLE_FTSEARCH
    if (!depth) init_ft_sequences(left,right,parent);
#endif
#ifdef SE_ENABLE_TRIGGERS
    if (parent == XNULL) {
        if (left != XNULL) {
            CHECKP(left);
            parent = removeIndirection(((n_dsc*) XADDR(left))->pdsc);
        } else {
            CHECKP(right);
            parent = removeIndirection(((n_dsc*) XADDR(right))->pdsc);
        }
    }

    node = apply_per_node_triggers(node, XNULL, parent, XNULL, TRIGGER_BEFORE,  TRIGGER_INSERT_EVENT);

    if (node == XNULL) {
        if (left == XNULL) { return XNULL; }
        CHECKP(left);
        return left;
    }
#endif

    node_indir = getIndirectionSafeCP(node);
    scmnode = getBlockHeaderCP(node)->snode;

    switch (scmnode->type) {
        case element: {
            xptr result_indir;
            xmlns_ptr ns = scmnode->get_xmlns();

            if (nsupdmap != NULL && ns != NULL_XMLNS) {
                swizzleNamespace(ns, *nsupdmap);
            }

            scm_type = (save_types) ? E_DSC(node)->type : xs_untyped;
            result = insert_element(left, right, parent, scmnode->name, scm_type, ns);
            result_indir = get_last_mo_inderection();

            copy_node_content(result_indir, indirectionDereferenceCP(node_indir), XNULL, nsupdmap, save_types, depth);

            result = indirectionDereferenceCP(result_indir);
            CHECKP(result);
                      }
                      break;

        case text: {
            if (isTextEmpty(T_DSC(node))) {
                throw SYSTEM_EXCEPTION("BAD DATA!!!");
            } else {
                xptr data = getTextPtr(T_DSC(node));
                CHECKP(node);
                result = insert_text(left, right, parent, &data, getTextSize(T_DSC(node)), text_doc);
            }
                   }
                   break;

        case cdata: {
            text_cptr buf(node);
            result = insert_cdata(left, right, parent, buf.get(), buf.getSize());
                    }
                    break;

        case comment: {
            text_cptr buf(node);
            result = insert_comment(left, right, parent, buf.get(), buf.getSize());
                      }
                      break;

        case pr_ins: {
            size_t tsize = PI_DSC(node)->target;
            text_cptr buf(node);
            result = insert_pi(left, right, parent, buf.get(), tsize, buf.get() + tsize + 1, buf.getSize() - tsize - 1);
                     }
                     break;

        case attribute: {
            xmlns_ptr ns = scmnode->get_xmlns();
            text_cptr buf(node);

            if (nsupdmap != NULL && ns != NULL_XMLNS) {
                swizzleNamespace(ns, *nsupdmap);
            }

            CHECKP(node);
            scm_type = (save_types) ? A_DSC(node)->type : xs_untypedAtomic;
            result = insert_attribute(left, right, parent, scmnode->name, scm_type, buf.get(), buf.getSize(), ns);
                        }
                        break;

        case xml_namespace: {
            xmlns_ptr ns = xmlns_touch(NS_DSC(node)->ns);
            if (nsupdmap != NULL && ns != NULL_XMLNS) {
                swizzleNamespace(ns, *nsupdmap);
            }
            result = insert_namespace(left, right, parent, ns);
                            }
                            break;

        default:
            throw SYSTEM_EXCEPTION("Deep copy error: document node copied");
    }

    CHECKP(result);

#ifdef SE_ENABLE_FTSEARCH
    update_insert_sequence(result, schema_node_cptr((GETBLOCKBYNODE(result))->snode));
#endif

#ifdef SE_ENABLE_TRIGGERS
    if (parent==XNULL) parent=removeIndirection(((n_dsc*)XADDR(left))->pdsc);
    apply_per_node_triggers(result, XNULL, parent, XNULL, TRIGGER_AFTER, TRIGGER_INSERT_EVENT);
#endif

    CHECKP(result);

    return result;
}

xptr copy_to_temp(xptr node)
{
    PPConstructor::checkInitial();
    return deep_copy_node(XNULL,
        XNULL,
        PPConstructor::get_virtual_root(),
        node,
        NULL,
        true);
}

<commit_msg>full-text updates fix<commit_after>/*
* File:  updates.cpp
* Copyright (C) 2004 The Institute for System Programming of the Russian Academy of Sciences (ISP RAS)
*/

#include "common/sedna.h"

#include "tr/updates/updates.h"
#include "tr/mo/mo.h"
#include "tr/crmutils/node_utils.h"
#include "tr/executor/base/xptr_sequence.h"
#include "tr/nid/numb_scheme.h"
#include "tr/executor/xqops/PPConstructors.h"
#include "tr/mo/indirection.h"

#ifdef SE_ENABLE_TRIGGERS
#include "tr/triggers/triggers.h"
#endif

#define IGNORE_UPDATE_ERRORS

#ifdef SE_ENABLE_FTSEARCH
std::map<ft_index_cell_xptr,update_history*> ft_updates;
#endif

#ifdef SE_ENABLE_FTSEARCH
void clear_ft_sequences()
{
    std::map<ft_index_cell_xptr,update_history*>::iterator it=ft_updates.begin();
    while (it!=ft_updates.end())
    {
        delete it->second;
        it++;
    }
    ft_updates.clear();
}
void execute_modifications()
{
    if (indirectionGetRollbackMode()) return;
    std::map<ft_index_cell_xptr,update_history*>::iterator it=ft_updates.begin();
    while (it!=ft_updates.end())
    {
        it->first->update_index(it->second);
        it++;
    }
	//FIXME: dirty fix for bug with missing clear_ft_sequences() call
	//TODO: remove this and add clear_ft_sequences() call or remove all other clear_ft_sequences() calls
	clear_ft_sequences();
}
void update_insert_sequence(xptr node,ft_index_cell_cptr icell)
{
    std::map<ft_index_cell_xptr,update_history*>::iterator it=ft_updates.find(icell.ptr());
    if (it==ft_updates.end())
    {
        update_history *h=se_new update_history();
		h->add_insert_node(node);
        ft_updates[icell.ptr()]=h;
    }
    else
        it->second->add_insert_node(node);

}
void update_update_sequence(xptr node,ft_index_cell_cptr icell)
{
    std::map<ft_index_cell_xptr,update_history*>::iterator it=ft_updates.find(icell.ptr());
    if (it==ft_updates.end())
    {
        update_history *h=se_new update_history();
        h->add_update_node(node);
        ft_updates[icell.ptr()]=h;
    }
    else
        it->second->add_update_node(node);
}
void update_delete_sequence(xptr node,ft_index_cell_cptr icell)
{
    std::map<ft_index_cell_xptr,update_history*>::iterator it=ft_updates.find(icell.ptr());
    if (it==ft_updates.end())
    {
        update_history* h=se_new update_history();
        h->add_delete_node(node);
        ft_updates[icell.ptr()]=h;
    }
    else
        it->second->add_delete_node(node);
}

void update_insert_sequence(xptr node,schema_node_cptr icell)
{
    cat_list<ft_index_cell_xptr>::item* obj=icell->ft_index_list.first;
    if (obj == NULL) return;
    CHECKP(node);
    xptr ind=((n_dsc*)XADDR(node))->indir;
    while (obj!=NULL)
    {
        update_insert_sequence(ind,ft_index_cell_cptr(obj->object));
        obj=obj->next;
    }
    CHECKP(node);
}

void update_update_sequence(xptr node,schema_node_cptr icell)
{
    cat_list<ft_index_cell_xptr>::item* obj=icell->ft_index_list.first;
    if (obj==NULL) return;
    CHECKP(node);
    xptr ind=((n_dsc*)XADDR(node))->indir;
    while (obj!=NULL)
    {
        update_update_sequence(ind,ft_index_cell_cptr(obj->object));
        obj=obj->next;
    }
    CHECKP(node);
}

void update_delete_sequence(xptr node,schema_node_cptr icell)
{
    cat_list<ft_index_cell_xptr>::item* obj=icell->ft_index_list.first;
    if (obj==NULL) return;
    CHECKP(node);
    xptr ind=((n_dsc*)XADDR(node))->indir;
    while (obj!=NULL)
    {
        update_delete_sequence(ind,ft_index_cell_cptr(obj->object));
        obj=obj->next;
    }
    CHECKP(node);
}

void init_ft_sequences (const xptr& left, const xptr& right, const xptr& parent)
{
    if (IS_TMP_BLOCK(left)||IS_TMP_BLOCK(right)||IS_TMP_BLOCK(parent)) return;
    xptr tmp;
    schema_node_cptr scn = XNULL;
    if (parent!=XNULL)
    {
        tmp=parent;
        CHECKP(parent);
        scn=(GETBLOCKBYNODE(parent))->snode;
    }
    else
    {
        tmp=(left==XNULL)?right:left;
        CHECKP(tmp);
        scn=(GETBLOCKBYNODE(tmp))->snode->parent;
    }

    if (scn->root == scn.ptr() || scn->root->full_ft_index_list.empty()) return;

    while (scn.found())
    {
        cat_list<ft_index_cell_xptr>::item* obj=scn->ft_index_list.first;
        if (obj!=NULL)
        {
            tmp=getNodeAncestorIndirectionByScheme(tmp,scn);
            while (obj!=NULL)
            {
                update_update_sequence(tmp,ft_index_cell_cptr(obj->object));
                obj=obj->next;
            }
            tmp=removeIndirection(tmp);
        }
        scn=scn->parent;
    }
}
#endif

xptr copy_node_content(xptr new_node_i, xptr node, xptr left_node_i, upd_ns_map** nsupdmap, bool save_types, unsigned short depth) {
    xptr left_node = XNULL;
    xptr childi = getIndirectionSafeCP(getFirstByOrderChildCP(node));

    while (childi != XNULL) {
        left_node = deep_copy_node_i(left_node_i, XNULL, new_node_i, indirectionDereferenceCP(childi), nsupdmap, save_types, depth + 1);

        /* due to : MG: deep_temp_copy can return XNULL if a trigger canceled
        * the insertion and there were now any left sibling */
        if (left_node != XNULL) {
            left_node_i = getIndirectionSafeCP(left_node);
        }

        childi = getRightSiblingIndirectionCP(indirectionDereferenceCP(childi));
    }

    return left_node_i;
}

void swizzleNamespace (xmlns_ptr & ns, upd_ns_map*& updmap)
{
    if (updmap == NULL) updmap = se_new upd_ns_map;
    upd_ns_map::const_iterator it = updmap->find(ns);
    if (it == updmap->end()) {
        ns = xmlns_touch(ns->prefix, ns->uri);
    } else {
        ns = it->second;
    }
}

xptr deep_copy_node(xptr left, xptr right, xptr parent, xptr node, upd_ns_map** nsupdmap, bool save_types, unsigned short depth)
{
    xptr result;
    xptr node_indir;
    schema_node_cptr scmnode;
    xmlscm_type scm_type;

#ifdef SE_ENABLE_FTSEARCH
    if (!depth) init_ft_sequences(left,right,parent);
#endif
#ifdef SE_ENABLE_TRIGGERS
    if (parent == XNULL) {
        if (left != XNULL) {
            CHECKP(left);
            parent = removeIndirection(((n_dsc*) XADDR(left))->pdsc);
        } else {
            CHECKP(right);
            parent = removeIndirection(((n_dsc*) XADDR(right))->pdsc);
        }
    }

    node = apply_per_node_triggers(node, XNULL, parent, XNULL, TRIGGER_BEFORE,  TRIGGER_INSERT_EVENT);

    if (node == XNULL) {
        if (left == XNULL) { return XNULL; }
        CHECKP(left);
        return left;
    }
#endif

    node_indir = getIndirectionSafeCP(node);
    scmnode = getBlockHeaderCP(node)->snode;

    switch (scmnode->type) {
        case element: {
            xptr result_indir;
            xmlns_ptr ns = scmnode->get_xmlns();

            if (nsupdmap != NULL && ns != NULL_XMLNS) {
                swizzleNamespace(ns, *nsupdmap);
            }

            scm_type = (save_types) ? E_DSC(node)->type : xs_untyped;
            result = insert_element(left, right, parent, scmnode->name, scm_type, ns);
            result_indir = get_last_mo_inderection();

            copy_node_content(result_indir, indirectionDereferenceCP(node_indir), XNULL, nsupdmap, save_types, depth);

            result = indirectionDereferenceCP(result_indir);
            CHECKP(result);
                      }
                      break;

        case text: {
            if (isTextEmpty(T_DSC(node))) {
                throw SYSTEM_EXCEPTION("BAD DATA!!!");
            } else {
                xptr data = getTextPtr(T_DSC(node));
                CHECKP(node);
                result = insert_text(left, right, parent, &data, getTextSize(T_DSC(node)), text_doc);
            }
                   }
                   break;

        case cdata: {
            text_cptr buf(node);
            result = insert_cdata(left, right, parent, buf.get(), buf.getSize());
                    }
                    break;

        case comment: {
            text_cptr buf(node);
            result = insert_comment(left, right, parent, buf.get(), buf.getSize());
                      }
                      break;

        case pr_ins: {
            size_t tsize = PI_DSC(node)->target;
            text_cptr buf(node);
            result = insert_pi(left, right, parent, buf.get(), tsize, buf.get() + tsize + 1, buf.getSize() - tsize - 1);
                     }
                     break;

        case attribute: {
            xmlns_ptr ns = scmnode->get_xmlns();
            text_cptr buf(node);

            if (nsupdmap != NULL && ns != NULL_XMLNS) {
                swizzleNamespace(ns, *nsupdmap);
            }

            CHECKP(node);
            scm_type = (save_types) ? A_DSC(node)->type : xs_untypedAtomic;
            result = insert_attribute(left, right, parent, scmnode->name, scm_type, buf.get(), buf.getSize(), ns);
                        }
                        break;

        case xml_namespace: {
            xmlns_ptr ns = xmlns_touch(NS_DSC(node)->ns);
            if (nsupdmap != NULL && ns != NULL_XMLNS) {
                swizzleNamespace(ns, *nsupdmap);
            }
            result = insert_namespace(left, right, parent, ns);
                            }
                            break;

        default:
            throw SYSTEM_EXCEPTION("Deep copy error: document node copied");
    }

    CHECKP(result);

#ifdef SE_ENABLE_FTSEARCH
    update_insert_sequence(result, schema_node_cptr((GETBLOCKBYNODE(result))->snode));
#endif

#ifdef SE_ENABLE_TRIGGERS
    if (parent==XNULL) parent=removeIndirection(((n_dsc*)XADDR(left))->pdsc);
    apply_per_node_triggers(result, XNULL, parent, XNULL, TRIGGER_AFTER, TRIGGER_INSERT_EVENT);
#endif

    CHECKP(result);

    return result;
}

xptr copy_to_temp(xptr node)
{
    PPConstructor::checkInitial();
    return deep_copy_node(XNULL,
        XNULL,
        PPConstructor::get_virtual_root(),
        node,
        NULL,
        true);
}

<|endoftext|>


<commit_before>/**
 * Mutable Fibonacci Heap implementation
 * © 2013 Philips Healthcare
 * Author: Maurice Termeer
 */

#ifndef _FIBONACCI_HEAP_
#define _FIBONACCI_HEAP_

#include <algorithm>
#include <deque>
#include <functional>
#include <iterator>
#include <list>
#include <map>
#include <utility>
#include <vector>

template<typename T>
class fibonacci_heap
{
public:
	struct node {
		T element;
		node* parent;
		std::vector<node*> children;
	};

	typedef T value_type;
	typedef std::size_t size_type;
	typedef const T& const_reference;
	typedef T& reference;
	typedef const node* const_pointer;
	typedef node* pointer;

	struct iterator {
		const_reference operator*() const {
			return p_->element;
		}

		reference operator*() {
			return p_->element;
		}

		iterator(pointer p) : p_(p) { }

		pointer p_;
	};

	fibonacci_heap()
		: n_(0) { }

	iterator top() const
	{
		return iterator(roots_.front());
	}

	void insert(const_reference element)
	{
		pointer new_node = allocator_.allocate(1);
		allocator_.construct(new_node);
		new_node->element = element;
		new_node->parent = nullptr;
		roots_.push_back(new_node);

		if (new_node->element < roots_.front()->element) {
			std::swap(roots_.front(), roots_.back());
		}

		++n_;
	}

	void pop()
	{
		pointer old_node = roots_.front();

		std::swap(roots_.front(), roots_.back());
		roots_.pop_back();

		std::for_each(
			std::begin(old_node->children), std::end(old_node->children),
				[&](pointer p) {
			roots_.push_back(p);
			p->parent = nullptr;
		});

		allocator_.deallocate(old_node, 1);

		merge_roots();

		--n_;
	}

private:
	void merge_roots()
	{
		std::vector<pointer> degrees;

		for (std::size_t i = 0; i < roots_.size(); ++i) {
			auto root = roots_[i];

			if (root->parent != nullptr) continue;

			auto degree = root->children.size();

			while (true) {
				if (degrees.size() <= degree) {
					degrees.resize(degree + 1);
				}

				auto k = degrees[degree];

				if (k == nullptr) {
					degrees[degree] = root;
					break;
				} else if (k == root) {
					break;
				} else {
					auto other = k;

					if (other->element < root->element) {
						other->children.push_back(root);
						root->parent = other;
						root = other;
					} else {
						root->children.push_back(other);
						other->parent = root;
					}

					degrees[degree] = nullptr;
					++degree;
				}
			}
		}

		roots_.clear();

		for (auto i = std::begin(degrees); i != std::end(degrees); ++i) {
			if (*i == nullptr) continue;
			roots_.push_back(*i);

			if (!(roots_.front()->element < (*i)->element)) {
				std::swap(roots_.front(), roots_.back());
			}
		}
	}

	std::deque<pointer> roots_;
	std::allocator<node> allocator_;
	size_type n_;
};

#endif // _FIBONACCI_HEAP_
<commit_msg>use constant-size array for degrees map<commit_after>/**
 * Mutable Fibonacci Heap implementation
 * © 2013 Philips Healthcare
 * Author: Maurice Termeer
 */

#ifndef _FIBONACCI_HEAP_
#define _FIBONACCI_HEAP_

#include <algorithm>
#include <array>
#include <deque>
#include <functional>
#include <iterator>
#include <list>
#include <map>
#include <utility>
#include <vector>

template<typename T>
class fibonacci_heap
{
public:
	struct node {
		T element;
		node* parent;
		std::vector<node*> children;
	};

	typedef T value_type;
	typedef std::size_t size_type;
	typedef const T& const_reference;
	typedef T& reference;
	typedef const node* const_pointer;
	typedef node* pointer;

	struct iterator {
		const_reference operator*() const {
			return p_->element;
		}

		reference operator*() {
			return p_->element;
		}

		iterator(pointer p) : p_(p) { }

		pointer p_;
	};

	fibonacci_heap()
		: n_(0) {
		degrees_.fill(nullptr);
	}

	iterator top() const
	{
		return iterator(roots_.front());
	}

	void insert(const_reference element)
	{
		pointer new_node = allocator_.allocate(1);
		allocator_.construct(new_node);
		new_node->element = element;
		new_node->parent = nullptr;
		roots_.push_back(new_node);

		if (new_node->element < roots_.front()->element) {
			std::swap(roots_.front(), roots_.back());
		}

		if (degrees_[0] == nullptr) {
			degrees_[0] = new_node;
		}

		++n_;
	}

	void pop()
	{
		pointer old_node = roots_.front();

		std::swap(roots_.front(), roots_.back());
		roots_.pop_back();

		std::size_t degree = old_node->children.size();
		if (degrees_[degree] == old_node) {
			degrees_[degree] = nullptr;
		}

		std::for_each(
			std::begin(old_node->children), std::end(old_node->children),
				[&](pointer p) {
			roots_.push_back(p);
			p->parent = nullptr;
		});

		allocator_.deallocate(old_node, 1);

		merge_roots();

		--n_;
	}

private:
	void merge_roots()
	{
		for (std::size_t i = 0; i < roots_.size(); ++i) {
			auto root = roots_[i];

			if (root->parent != nullptr) continue;

			auto degree = root->children.size();

			while (true) {
				auto k = degrees_[degree];

				if (k == nullptr) {
					degrees_[degree] = root;
					break;
				} else if (k == root) {
					break;
				} else {
					auto other = k;

					if (other->element < root->element) {
						other->children.push_back(root);
						root->parent = other;
						root = other;
					} else {
						root->children.push_back(other);
						other->parent = root;
					}

					degrees_[degree] = nullptr;
					++degree;
				}
			}
		}

		roots_.clear();

		for (auto i = std::begin(degrees_); i != std::end(degrees_); ++i) {
			if (*i == nullptr) continue;
			roots_.push_back(*i);

			if (!(roots_.front()->element < (*i)->element)) {
				std::swap(roots_.front(), roots_.back());
			}
		}
	}

	std::array<pointer,sizeof(std::size_t) * 8> degrees_;
	std::deque<pointer> roots_;
	std::allocator<node> allocator_;
	size_type n_;
};

#endif // _FIBONACCI_HEAP_
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-2007 Rony Shapiro <ronys@users.sourceforge.net>.
 * All rights reserved. Use of the code is allowed under the
 * Artistic License 2.0 terms, as specified in the LICENSE file
 * distributed with this code, or available from
 * http://www.opensource.org/licenses/artistic-license-2.0.php
 */
// ExpPWListDlg.cpp : implementation file
//

#include "stdafx.h"
#include "ExpPWListDlg.h"
#include "DboxMain.h"
#include "corelib/MyString.h"
#include "corelib/Util.h"
#include "corelib/ItemData.h"
#include "resource2.h"  // Menu, Toolbar & Accelerator resources
#include "resource3.h"  // String resources

using namespace std;

ExpPWEntry::ExpPWEntry(const CItemData &ci, time_t now, time_t LTime)
{
  group = ci.GetGroup();
  title = ci.GetTitle();
  user = ci.GetUser();
  // Expired or Warning / Normal or Base - see image list below
  type = (LTime <= now ? 0 : 1) + (ci.IsBase() ? 2 : 0);
  expirylocdate = ci.GetLTimeL();
  expiryexpdate = ci.GetLTimeExp();
  expirytttdate = LTime;
}

// CExpPWListDlg dialog

CExpPWListDlg::CExpPWListDlg(CWnd* pParent,
                             const ExpiredList &expPWList,
                             const CString& a_filespec)
	: CPWDialog(CExpPWListDlg::IDD, pParent), m_expPWList(expPWList)
{
	const int FILE_DISP_LEN = 75;

	if (a_filespec.GetLength() > FILE_DISP_LEN) {
    // m_message = a_filespec.Right(FILE_DISP_LEN - 3); // truncate for display
    // m_message.Insert(0, _T("..."));
		m_message =  a_filespec.Left(FILE_DISP_LEN/2-5) +
      _T(" ... ") + a_filespec.Right(FILE_DISP_LEN/2);
	} else {
		m_message = a_filespec;
	}

	m_iSortedColumn = -1;
	m_bSortAscending = TRUE;
}

CExpPWListDlg::~CExpPWListDlg()
{
}

void CExpPWListDlg::DoDataExchange(CDataExchange* pDX)
{
	CPWDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EXPIRED_PASSWORD_LIST, m_expPWListCtrl);
	DDX_Text(pDX, IDC_MESSAGE, m_message);
}

BEGIN_MESSAGE_MAP(CExpPWListDlg, CPWDialog)
ON_BN_CLICKED(IDC_COPY_EXP_TO_CLIPBOARD, OnBnClickedCopyExpToClipboard)
ON_BN_CLICKED(IDOK, OnOK)
ON_NOTIFY(HDN_ITEMCLICKA, 0, OnHeaderClicked)
ON_NOTIFY(HDN_ITEMCLICKW, 0, OnHeaderClicked)
END_MESSAGE_MAP()

// CExpPWListDlg message handlers

BOOL
CExpPWListDlg::OnInitDialog()
{
	CPWDialog::OnInitDialog();

  //m_expPWListCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_SUBITEMIMAGES );

	CString cs_text;
  m_expPWListCtrl.InsertColumn(0, _T(""));
	cs_text.LoadString(IDS_GROUP);
	m_expPWListCtrl.InsertColumn(1, cs_text);
	cs_text.LoadString(IDS_TITLE);
	m_expPWListCtrl.InsertColumn(3, cs_text);
	cs_text.LoadString(IDS_USERNAME);
	m_expPWListCtrl.InsertColumn(3, cs_text);
	cs_text.LoadString(IDS_EXPIRYDATETIME);
	m_expPWListCtrl.InsertColumn(4, cs_text);

  m_pImageList = new CImageList();
  // Number (4) same as total of warn/expired images below
  BOOL status = m_pImageList->Create(9, 9, ILC_COLOR, 4, 0);
  ASSERT(status != 0);
  CBitmap bitmap;

  bitmap.LoadBitmap(IDB_LEAF_EXPIRED);
  m_pImageList->Add(&bitmap, (COLORREF)0x0);
  bitmap.DeleteObject();
  bitmap.LoadBitmap(IDB_LEAF_WARNEXPIRED);
  m_pImageList->Add(&bitmap, (COLORREF)0x0);
  bitmap.DeleteObject();
  bitmap.LoadBitmap(IDB_LEAF_BASE_EXPIRED);
  m_pImageList->Add(&bitmap, (COLORREF)0x0);
  bitmap.DeleteObject();
  bitmap.LoadBitmap(IDB_LEAF_BASE_WARNEXPIRED);
  m_pImageList->Add(&bitmap, (COLORREF)0x0);
  bitmap.DeleteObject();
  m_expPWListCtrl.SetImageList(m_pImageList, LVSIL_SMALL);
  m_expPWListCtrl.SetImageList(m_pImageList, LVSIL_NORMAL);

  int nPos = 0;
  ExpiredList::const_iterator itempos;

  for (itempos = m_expPWList.begin();
       itempos != m_expPWList.end();
       itempos++) {
		const ExpPWEntry exppwentry = *itempos;
		nPos = m_expPWListCtrl.InsertItem(nPos, NULL, exppwentry.type);
    m_expPWListCtrl.SetItemText(nPos, 1, exppwentry.group);
		m_expPWListCtrl.SetItemText(nPos, 2, exppwentry.title);
		m_expPWListCtrl.SetItemText(nPos, 3, exppwentry.user);
		m_expPWListCtrl.SetItemText(nPos, 4, exppwentry.expirylocdate);
    // original nPos == index in vector: save for Sort
		m_expPWListCtrl.SetItemData(nPos, static_cast<DWORD>(nPos));
	}

	m_expPWListCtrl.SetRedraw(FALSE);
	for (int i = 0; i < 5; i++) {
		m_expPWListCtrl.SetColumnWidth(i, LVSCW_AUTOSIZE);
		int nColumnWidth = m_expPWListCtrl.GetColumnWidth(i);
		m_expPWListCtrl.SetColumnWidth(i, LVSCW_AUTOSIZE_USEHEADER);
		int nHeaderWidth = m_expPWListCtrl.GetColumnWidth(i);
		m_expPWListCtrl.SetColumnWidth(i, max(nColumnWidth, nHeaderWidth));
	}
	m_expPWListCtrl.SetRedraw(TRUE);

	return TRUE;
}

void
CExpPWListDlg::OnOK()
{
  delete m_pImageList;
	CPWDialog::OnOK();
}

void
CExpPWListDlg::OnBnClickedCopyExpToClipboard()
{
	CString data(MAKEINTRESOURCE(IDS_COPYTITLE));
	const CString CRLF = _T("\r\n");
	const CString TAB = _T('\t');

  ExpiredList::const_iterator itempos;

  for (itempos = m_expPWList.begin();
       itempos != m_expPWList.end();
       itempos++) {
		const ExpPWEntry exppwentry = *itempos;
		data = data +
			(CString)exppwentry.group + TAB +
			(CString)exppwentry.title + TAB +
			(CString)exppwentry.user + TAB +
			(CString)exppwentry.expiryexpdate + CRLF;
	}

  DboxMain *dbx = static_cast<DboxMain *>(GetParent());
  dbx->SetClipboardData(data);
}

void
CExpPWListDlg::OnHeaderClicked(NMHDR* pNMHDR, LRESULT* pResult)
{
	HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;

	if(phdn->iButton == 0) {
		// User clicked on header using left mouse button
		if(phdn->iItem == m_iSortedColumn)
			m_bSortAscending = !m_bSortAscending;
		else
			m_bSortAscending = TRUE;

		m_iSortedColumn = phdn->iItem;
		m_expPWListCtrl.SortItems(ExpPWCompareFunc, (LPARAM)this);

		// Note: WINVER defines the minimum system level for which this is program compiled and
		// NOT the level of system it is running on!
		// In this case, these values are defined in Windows XP and later and supported
		// by V6 of comctl32.dll (supplied with Windows XP) and later.
		// They should be ignored by earlier levels of this dll or .....
		//     we can check the dll version (code available on request)!

#if (WINVER < 0x0501)	// These are already defined for WinXP and later
#define HDF_SORTUP 0x0400
#define HDF_SORTDOWN 0x0200
#endif
		HDITEM HeaderItem;
		HeaderItem.mask = HDI_FORMAT;
		m_expPWListCtrl.GetHeaderCtrl()->GetItem(m_iSortedColumn, &HeaderItem);
		// Turn off all arrows
		HeaderItem.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
		// Turn on the correct arrow
		HeaderItem.fmt |= ((m_bSortAscending == TRUE) ? HDF_SORTUP : HDF_SORTDOWN);
		m_expPWListCtrl.GetHeaderCtrl()->SetItem(m_iSortedColumn, &HeaderItem);
	}

	*pResult = 0;
}

int CALLBACK CExpPWListDlg::ExpPWCompareFunc(LPARAM lParam1, LPARAM lParam2,
										LPARAM closure)
{
	CExpPWListDlg *self = (CExpPWListDlg*)closure;
	int nSortColumn = self->m_iSortedColumn;
	const ExpPWEntry pLHS = self->m_expPWList[lParam1];
	const ExpPWEntry pRHS = self->m_expPWList[lParam2];
	CMyString group1, title1, username1;
	CMyString group2, title2, username2;
    int type1, type2;
	time_t t1, t2;

	int iResult;
	switch(nSortColumn) {
		case 0:
			type1 = pLHS.type;
			type2 = pRHS.type;
			iResult = (type1 < type2) ? -1 : 1;
			break;
		case 1:
			group1 = pLHS.group;
			group2 = pRHS.group;
			iResult = ((CString)group1).CompareNoCase(group2);
			break;
		case 2:
			title1 = pLHS.title;
			title2 = pRHS.title;
			iResult = ((CString)title1).CompareNoCase(title2);
			break;
		case 3:
			username1 = pLHS.user;
			username2 = pRHS.user;
			iResult = ((CString)username1).CompareNoCase(username2);
			break;
		case 4:
			t1 = pLHS.expirytttdate;
			t2 = pRHS.expirytttdate;
			iResult = ((long) t1 < (long) t2) ? -1 : 1;
			break;
		default:
		    iResult = 0; // should never happen - just keep compiler happy
			ASSERT(FALSE);
	}

	if (!self->m_bSortAscending)
		iResult *= -1;

	return iResult;
}
<commit_msg>Correct column number in Expired Password dialog<commit_after>/*
 * Copyright (c) 2003-2007 Rony Shapiro <ronys@users.sourceforge.net>.
 * All rights reserved. Use of the code is allowed under the
 * Artistic License 2.0 terms, as specified in the LICENSE file
 * distributed with this code, or available from
 * http://www.opensource.org/licenses/artistic-license-2.0.php
 */
// ExpPWListDlg.cpp : implementation file
//

#include "stdafx.h"
#include "ExpPWListDlg.h"
#include "DboxMain.h"
#include "corelib/MyString.h"
#include "corelib/Util.h"
#include "corelib/ItemData.h"
#include "resource2.h"  // Menu, Toolbar & Accelerator resources
#include "resource3.h"  // String resources

using namespace std;

ExpPWEntry::ExpPWEntry(const CItemData &ci, time_t now, time_t LTime)
{
  group = ci.GetGroup();
  title = ci.GetTitle();
  user = ci.GetUser();
  // Expired or Warning / Normal or Base - see image list below
  type = (LTime <= now ? 0 : 1) + (ci.IsBase() ? 2 : 0);
  expirylocdate = ci.GetLTimeL();
  expiryexpdate = ci.GetLTimeExp();
  expirytttdate = LTime;
}

// CExpPWListDlg dialog

CExpPWListDlg::CExpPWListDlg(CWnd* pParent,
                             const ExpiredList &expPWList,
                             const CString& a_filespec)
	: CPWDialog(CExpPWListDlg::IDD, pParent), m_expPWList(expPWList)
{
	const int FILE_DISP_LEN = 75;

	if (a_filespec.GetLength() > FILE_DISP_LEN) {
    // m_message = a_filespec.Right(FILE_DISP_LEN - 3); // truncate for display
    // m_message.Insert(0, _T("..."));
		m_message =  a_filespec.Left(FILE_DISP_LEN/2-5) +
      _T(" ... ") + a_filespec.Right(FILE_DISP_LEN/2);
	} else {
		m_message = a_filespec;
	}

	m_iSortedColumn = -1;
	m_bSortAscending = TRUE;
}

CExpPWListDlg::~CExpPWListDlg()
{
}

void CExpPWListDlg::DoDataExchange(CDataExchange* pDX)
{
	CPWDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EXPIRED_PASSWORD_LIST, m_expPWListCtrl);
	DDX_Text(pDX, IDC_MESSAGE, m_message);
}

BEGIN_MESSAGE_MAP(CExpPWListDlg, CPWDialog)
ON_BN_CLICKED(IDC_COPY_EXP_TO_CLIPBOARD, OnBnClickedCopyExpToClipboard)
ON_BN_CLICKED(IDOK, OnOK)
ON_NOTIFY(HDN_ITEMCLICKA, 0, OnHeaderClicked)
ON_NOTIFY(HDN_ITEMCLICKW, 0, OnHeaderClicked)
END_MESSAGE_MAP()

// CExpPWListDlg message handlers

BOOL
CExpPWListDlg::OnInitDialog()
{
	CPWDialog::OnInitDialog();

  //m_expPWListCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_SUBITEMIMAGES );

	CString cs_text;
  m_expPWListCtrl.InsertColumn(0, _T(""));
	cs_text.LoadString(IDS_GROUP);
	m_expPWListCtrl.InsertColumn(1, cs_text);
	cs_text.LoadString(IDS_TITLE);
	m_expPWListCtrl.InsertColumn(2, cs_text);
	cs_text.LoadString(IDS_USERNAME);
	m_expPWListCtrl.InsertColumn(3, cs_text);
	cs_text.LoadString(IDS_EXPIRYDATETIME);
	m_expPWListCtrl.InsertColumn(4, cs_text);

  m_pImageList = new CImageList();
  // Number (4) same as total of warn/expired images below
  BOOL status = m_pImageList->Create(9, 9, ILC_COLOR, 4, 0);
  ASSERT(status != 0);
  CBitmap bitmap;

  bitmap.LoadBitmap(IDB_LEAF_EXPIRED);
  m_pImageList->Add(&bitmap, (COLORREF)0x0);
  bitmap.DeleteObject();
  bitmap.LoadBitmap(IDB_LEAF_WARNEXPIRED);
  m_pImageList->Add(&bitmap, (COLORREF)0x0);
  bitmap.DeleteObject();
  bitmap.LoadBitmap(IDB_LEAF_BASE_EXPIRED);
  m_pImageList->Add(&bitmap, (COLORREF)0x0);
  bitmap.DeleteObject();
  bitmap.LoadBitmap(IDB_LEAF_BASE_WARNEXPIRED);
  m_pImageList->Add(&bitmap, (COLORREF)0x0);
  bitmap.DeleteObject();
  m_expPWListCtrl.SetImageList(m_pImageList, LVSIL_SMALL);
  m_expPWListCtrl.SetImageList(m_pImageList, LVSIL_NORMAL);

  int nPos = 0;
  ExpiredList::const_iterator itempos;

  for (itempos = m_expPWList.begin();
       itempos != m_expPWList.end();
       itempos++) {
		const ExpPWEntry exppwentry = *itempos;
		nPos = m_expPWListCtrl.InsertItem(nPos, NULL, exppwentry.type);
    m_expPWListCtrl.SetItemText(nPos, 1, exppwentry.group);
		m_expPWListCtrl.SetItemText(nPos, 2, exppwentry.title);
		m_expPWListCtrl.SetItemText(nPos, 3, exppwentry.user);
		m_expPWListCtrl.SetItemText(nPos, 4, exppwentry.expirylocdate);
    // original nPos == index in vector: save for Sort
		m_expPWListCtrl.SetItemData(nPos, static_cast<DWORD>(nPos));
	}

	m_expPWListCtrl.SetRedraw(FALSE);
	for (int i = 0; i < 5; i++) {
		m_expPWListCtrl.SetColumnWidth(i, LVSCW_AUTOSIZE);
		int nColumnWidth = m_expPWListCtrl.GetColumnWidth(i);
		m_expPWListCtrl.SetColumnWidth(i, LVSCW_AUTOSIZE_USEHEADER);
		int nHeaderWidth = m_expPWListCtrl.GetColumnWidth(i);
		m_expPWListCtrl.SetColumnWidth(i, max(nColumnWidth, nHeaderWidth));
	}
	m_expPWListCtrl.SetRedraw(TRUE);

	return TRUE;
}

void
CExpPWListDlg::OnOK()
{
  delete m_pImageList;
	CPWDialog::OnOK();
}

void
CExpPWListDlg::OnBnClickedCopyExpToClipboard()
{
	CString data(MAKEINTRESOURCE(IDS_COPYTITLE));
	const CString CRLF = _T("\r\n");
	const CString TAB = _T('\t');

  ExpiredList::const_iterator itempos;

  for (itempos = m_expPWList.begin();
       itempos != m_expPWList.end();
       itempos++) {
		const ExpPWEntry exppwentry = *itempos;
		data = data +
			(CString)exppwentry.group + TAB +
			(CString)exppwentry.title + TAB +
			(CString)exppwentry.user + TAB +
			(CString)exppwentry.expiryexpdate + CRLF;
	}

  DboxMain *dbx = static_cast<DboxMain *>(GetParent());
  dbx->SetClipboardData(data);
}

void
CExpPWListDlg::OnHeaderClicked(NMHDR* pNMHDR, LRESULT* pResult)
{
	HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;

	if(phdn->iButton == 0) {
		// User clicked on header using left mouse button
		if(phdn->iItem == m_iSortedColumn)
			m_bSortAscending = !m_bSortAscending;
		else
			m_bSortAscending = TRUE;

		m_iSortedColumn = phdn->iItem;
		m_expPWListCtrl.SortItems(ExpPWCompareFunc, (LPARAM)this);

		// Note: WINVER defines the minimum system level for which this is program compiled and
		// NOT the level of system it is running on!
		// In this case, these values are defined in Windows XP and later and supported
		// by V6 of comctl32.dll (supplied with Windows XP) and later.
		// They should be ignored by earlier levels of this dll or .....
		//     we can check the dll version (code available on request)!

#if (WINVER < 0x0501)	// These are already defined for WinXP and later
#define HDF_SORTUP 0x0400
#define HDF_SORTDOWN 0x0200
#endif
		HDITEM HeaderItem;
		HeaderItem.mask = HDI_FORMAT;
		m_expPWListCtrl.GetHeaderCtrl()->GetItem(m_iSortedColumn, &HeaderItem);
		// Turn off all arrows
		HeaderItem.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
		// Turn on the correct arrow
		HeaderItem.fmt |= ((m_bSortAscending == TRUE) ? HDF_SORTUP : HDF_SORTDOWN);
		m_expPWListCtrl.GetHeaderCtrl()->SetItem(m_iSortedColumn, &HeaderItem);
	}

	*pResult = 0;
}

int CALLBACK CExpPWListDlg::ExpPWCompareFunc(LPARAM lParam1, LPARAM lParam2,
										LPARAM closure)
{
	CExpPWListDlg *self = (CExpPWListDlg*)closure;
	int nSortColumn = self->m_iSortedColumn;
	const ExpPWEntry pLHS = self->m_expPWList[lParam1];
	const ExpPWEntry pRHS = self->m_expPWList[lParam2];
	CMyString group1, title1, username1;
	CMyString group2, title2, username2;
    int type1, type2;
	time_t t1, t2;

	int iResult;
	switch(nSortColumn) {
		case 0:
			type1 = pLHS.type;
			type2 = pRHS.type;
			iResult = (type1 < type2) ? -1 : 1;
			break;
		case 1:
			group1 = pLHS.group;
			group2 = pRHS.group;
			iResult = ((CString)group1).CompareNoCase(group2);
			break;
		case 2:
			title1 = pLHS.title;
			title2 = pRHS.title;
			iResult = ((CString)title1).CompareNoCase(title2);
			break;
		case 3:
			username1 = pLHS.user;
			username2 = pRHS.user;
			iResult = ((CString)username1).CompareNoCase(username2);
			break;
		case 4:
			t1 = pLHS.expirytttdate;
			t2 = pRHS.expirytttdate;
			iResult = ((long) t1 < (long) t2) ? -1 : 1;
			break;
		default:
		    iResult = 0; // should never happen - just keep compiler happy
			ASSERT(FALSE);
	}

	if (!self->m_bSortAscending)
		iResult *= -1;

	return iResult;
}
<|endoftext|>


<commit_before>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011-2016 Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Affero General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#include "../vld.h"
#include <fstream>
#include <iostream>
#ifdef _WIN32
#	include <conio.h>
#	include <ws2tcpip.h>
#endif
#include "../Interface/Server.h"
#include "CTCPFileServ.h"
#include "settings.h"
#include "../stringtools.h"
#include "log.h"

std::fstream logfile;
CTCPFileServ *TCPServer=NULL;

#ifdef LINUX
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#endif
#include <algorithm>

#ifdef DLL_EXPORT
#	define EXPORT_METHOD_INT 5
#endif

#ifdef _WIN32
void RestartServer()
{
	_u16 tcpport=TCPServer->getTCPPort();
	_u16 udpport=TCPServer->getUDPPort();
	std::string servername=TCPServer->getServername();
	bool use_fqdn=TCPServer->getUseFQDN();

	TCPServer->KickClients();
	delete TCPServer;
	Sleep(1000);

	TCPServer=new CTCPFileServ;
	int tries=20;
	while(!TCPServer->Start(tcpport, udpport, servername, use_fqdn) )
	{
		Sleep(1000);
		if(tries<=0)
		{
			_exit(32);
		}
		--tries;
	}
}

bool EnumerateInterfaces()
{
	static std::vector<std::vector<char> > ips;
	char hostname[MAX_PATH];

    _i32 rc=gethostname(hostname, MAX_PATH);
     if(rc==SOCKET_ERROR)
		return false;

	 bool new_ifs=false;

	 std::vector<std::vector<char> > new_ips;

	 struct addrinfo* h;
	 if(getaddrinfo(hostname, NULL, NULL, &h)==0)
     {
		 for(addrinfo* ptr = h;ptr!=NULL;ptr=ptr->ai_next)
		 {
			 if(ptr->ai_family==AF_INET || ptr->ai_family==AF_INET6)
			 {
				 std::vector<char> address;
				 address.resize(ptr->ai_addrlen);
				 memcpy(&address[0], ptr->ai_addr, ptr->ai_addrlen);

				 if(std::find(ips.begin(), ips.end(), address)==ips.end())
				 {
					 new_ifs=true;
				 }

				 new_ips.push_back(address);
			 }
		 }

		 freeaddrinfo(h);
     }

	 for(size_t i=0;i<ips.size();++i)
	 {
		 if(std::find(new_ips.begin(), new_ips.end(), ips[i])==new_ips.end())
		 {
			 new_ifs=true;
		 }
	 }

	 ips=new_ips;

	 return new_ifs;
}

void LookForInterfaceChanges()
{
	static int num=-1;
	if(num>=10 )
	{
		num=0;
		if(EnumerateInterfaces()==true)
		{
			RestartServer();
		}
	}
	if( num==-1 )
		EnumerateInterfaces();
	++num;
}

HRESULT ModifyPrivilege(
    IN LPCTSTR szPrivilege,
    IN BOOL fEnable)
{
    HRESULT hr = S_OK;
    TOKEN_PRIVILEGES NewState;
    LUID             luid;
    HANDLE hToken    = NULL;

    // Open the process token for this process.
    if (!OpenProcessToken(GetCurrentProcess(),
                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
                          &hToken ))
    {
        Log("Failed OpenProcessToken", LL_ERROR);
        return ERROR_FUNCTION_FAILED;
    }

    // Get the local unique ID for the privilege.
    if ( !LookupPrivilegeValue( NULL,
                                szPrivilege,
                                &luid ))
    {
        CloseHandle( hToken );
        Log("Failed LookupPrivilegeValue", LL_ERROR);
        return ERROR_FUNCTION_FAILED;
    }

    // Assign values to the TOKEN_PRIVILEGE structure.
    NewState.PrivilegeCount = 1;
    NewState.Privileges[0].Luid = luid;
    NewState.Privileges[0].Attributes =
              (fEnable ? SE_PRIVILEGE_ENABLED : 0);

    // Adjust the token privilege.
    if (!AdjustTokenPrivileges(hToken,
                               FALSE,
                               &NewState,
                               0,
                               NULL,
                               NULL))
    {
        Log("Failed AdjustTokenPrivileges", LL_ERROR);
        hr = ERROR_FUNCTION_FAILED;
    }

    // Close the handle.
    CloseHandle(hToken);

    return hr;
}

bool optain_backup_privs()
{
#ifdef BACKUP_SEM
	bool ret = true;
	HRESULT hr = ModifyPrivilege(SE_BACKUP_NAME, TRUE);
	if (!SUCCEEDED(hr))
	{
		Log("Failed to modify backup privileges", LL_ERROR);
		ret = false;
	}
	else
	{
		Log("Backup privileges set successfully", LL_DEBUG);
	}
	hr = ModifyPrivilege(SE_SECURITY_NAME, TRUE);
	if (!SUCCEEDED(hr))
	{
		Log("Failed to modify backup privileges (SE_SECURITY_NAME)", LL_ERROR);
		ret = false;
	}
	else
	{
		Log("Backup privileges set successfully (SE_SECURITY_NAME)", LL_DEBUG);
	}
	hr = ModifyPrivilege(SE_RESTORE_NAME, TRUE);
	if (!SUCCEEDED(hr))
	{
		Log("Failed to modify backup privileges (SE_RESTORE_NAME)", LL_ERROR);
		ret = false;
	}
	else
	{
		Log("Backup privileges set successfully (SE_RESTORE_NAME)", LL_DEBUG);
	}
	return ret;
#else
	return false;
#endif
}
#endif //_WIN32

#ifdef LINUX_DAEMON
bool c_run=true;
void termination_handler(int signum)
{
	c_run=false;
	_exit(2);
}
#endif

#ifdef CONSOLE_ON
int main(int argc, char* argv[])
{
#elif AS_SERVICE
void my_init_fcn(void)
{
#elif EXPORT_METHOD_INT
int start_server_int(unsigned short tcpport, unsigned short udpport, const std::string &pSname, const bool *pDostop, bool use_fqdn)
{
#else
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
#endif

#ifdef _DEBUG
	{
#endif
#ifdef LINUX_DAEMON
		std::cout << "Starting as Daemon..." << std::endl;
		if( fork()==0 )
		{
			setsid();
			for (int i=getdtablesize();i>=0;--i) close(i);
			int i=open("/dev/null",O_RDWR);
			dup(i);
			dup(i);
		}
		else
			exit(0);

		if (signal (SIGINT, termination_handler) == SIG_IGN)
			signal (SIGINT, SIG_IGN);
		if (signal (SIGHUP, termination_handler) == SIG_IGN)
			signal (SIGHUP, SIG_IGN);
		if (signal (SIGTERM, termination_handler) == SIG_IGN)
			signal (SIGTERM, SIG_IGN);

		c_run=true;
#endif

#ifndef _DEBUG
#ifndef AS_SERVICE
#ifndef EXPORT_METHOD_INT
	WriteReg();
#endif
#endif
#endif

	std::string servername;

#ifdef CONSOLE_ON
	if(argc==2)
		servername=argv[1];
#endif

	optain_backup_privs();

#ifdef LOG_FILE
#ifdef _WIN32
	logfile.open("C:\\urinstallsrv.log", std::ios::out | std::ios::binary );
#else
	logfile.open("/var/log/urinstallsrv.log", std::ios::out | std::ios::binary );
#endif
#endif

	/*std::fstream out(testfilename.c_str(), std::ios::out | std::ios::binary );
	if( out.is_open()==false )
		Log("Can't create testfile... Could perhaps cause problems.");

	char* buffer=new char[1024];
	for(size_t i=0;i<1024;++i)
		out.write(buffer, 1024);
	out.close();
	delete[] buffer;
*/

#ifdef _WIN32
	SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
#endif

	TCPServer=new CTCPFileServ;

#ifndef EXPORT_METHOD_INT
	bool suc=TCPServer->Start(55634,55635,servername);
#else
	bool suc=TCPServer->Start(tcpport, udpport, (pSname=="")?servername:pSname, use_fqdn);
#endif

	if(suc==false)
	{
		delete TCPServer;
		TCPServer=NULL;

#ifdef _WIN32
		SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
#endif
		return 99;
	}

#ifndef AS_SERVICE
	while(true)
	{
#if defined(_DEBUG) && defined(_WIN32)
		if( _kbhit() )
		{
			break;
		}
#endif
		bool b=TCPServer->Run();

		if( b==false )
			break;

#ifdef LINUX_DEAMON
		if( c_run==false )
			break;
#endif
#if EXPORT_METHOD_INT
		if(*pDostop==true)
		{
			TCPServer->KickClients();
			break;
		}
#endif
	}

	delete TCPServer;
#endif //AS_SERVICE

#ifdef _WIN32
	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
#endif

#ifndef AS_SERVICE
	return 2;
#endif
#ifdef _DEBUG
	}
#endif
}

<commit_msg>Obtain backup/restore privileges on Windows to read symlinks<commit_after>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011-2016 Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Affero General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#include "../vld.h"
#include <fstream>
#include <iostream>
#ifdef _WIN32
#	include <conio.h>
#	include <ws2tcpip.h>
#endif
#include "../Interface/Server.h"
#include "CTCPFileServ.h"
#include "settings.h"
#include "../stringtools.h"
#include "log.h"

std::fstream logfile;
CTCPFileServ *TCPServer=NULL;

#ifdef LINUX
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#endif
#include <algorithm>

#ifdef DLL_EXPORT
#	define EXPORT_METHOD_INT 5
#endif

#ifdef _WIN32
void RestartServer()
{
	_u16 tcpport=TCPServer->getTCPPort();
	_u16 udpport=TCPServer->getUDPPort();
	std::string servername=TCPServer->getServername();
	bool use_fqdn=TCPServer->getUseFQDN();

	TCPServer->KickClients();
	delete TCPServer;
	Sleep(1000);

	TCPServer=new CTCPFileServ;
	int tries=20;
	while(!TCPServer->Start(tcpport, udpport, servername, use_fqdn) )
	{
		Sleep(1000);
		if(tries<=0)
		{
			_exit(32);
		}
		--tries;
	}
}

bool EnumerateInterfaces()
{
	static std::vector<std::vector<char> > ips;
	char hostname[MAX_PATH];

    _i32 rc=gethostname(hostname, MAX_PATH);
     if(rc==SOCKET_ERROR)
		return false;

	 bool new_ifs=false;

	 std::vector<std::vector<char> > new_ips;

	 struct addrinfo* h;
	 if(getaddrinfo(hostname, NULL, NULL, &h)==0)
     {
		 for(addrinfo* ptr = h;ptr!=NULL;ptr=ptr->ai_next)
		 {
			 if(ptr->ai_family==AF_INET || ptr->ai_family==AF_INET6)
			 {
				 std::vector<char> address;
				 address.resize(ptr->ai_addrlen);
				 memcpy(&address[0], ptr->ai_addr, ptr->ai_addrlen);

				 if(std::find(ips.begin(), ips.end(), address)==ips.end())
				 {
					 new_ifs=true;
				 }

				 new_ips.push_back(address);
			 }
		 }

		 freeaddrinfo(h);
     }

	 for(size_t i=0;i<ips.size();++i)
	 {
		 if(std::find(new_ips.begin(), new_ips.end(), ips[i])==new_ips.end())
		 {
			 new_ifs=true;
		 }
	 }

	 ips=new_ips;

	 return new_ifs;
}

void LookForInterfaceChanges()
{
	static int num=-1;
	if(num>=10 )
	{
		num=0;
		if(EnumerateInterfaces()==true)
		{
			RestartServer();
		}
	}
	if( num==-1 )
		EnumerateInterfaces();
	++num;
}

HRESULT ModifyPrivilege(
    IN LPCTSTR szPrivilege,
    IN BOOL fEnable)
{
    HRESULT hr = S_OK;
    TOKEN_PRIVILEGES NewState;
    LUID             luid;
    HANDLE hToken    = NULL;

    // Open the process token for this process.
    if (!OpenProcessToken(GetCurrentProcess(),
                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
                          &hToken ))
    {
        Log("Failed OpenProcessToken", LL_ERROR);
        return ERROR_FUNCTION_FAILED;
    }

    // Get the local unique ID for the privilege.
    if ( !LookupPrivilegeValue( NULL,
                                szPrivilege,
                                &luid ))
    {
        CloseHandle( hToken );
        Log("Failed LookupPrivilegeValue", LL_ERROR);
        return ERROR_FUNCTION_FAILED;
    }

    // Assign values to the TOKEN_PRIVILEGE structure.
    NewState.PrivilegeCount = 1;
    NewState.Privileges[0].Luid = luid;
    NewState.Privileges[0].Attributes =
              (fEnable ? SE_PRIVILEGE_ENABLED : 0);

    // Adjust the token privilege.
    if (!AdjustTokenPrivileges(hToken,
                               FALSE,
                               &NewState,
                               0,
                               NULL,
                               NULL))
    {
        Log("Failed AdjustTokenPrivileges", LL_ERROR);
        hr = ERROR_FUNCTION_FAILED;
    }

    // Close the handle.
    CloseHandle(hToken);

    return hr;
}

bool optain_backup_privs()
{
#ifdef BACKUP_SEM
	bool ret = true;
	HRESULT hr = ModifyPrivilege(SE_BACKUP_NAME, TRUE);
	if (!SUCCEEDED(hr))
	{
		Log("Failed to modify backup privileges", LL_ERROR);
		ret = false;
	}
	else
	{
		Log("Backup privileges set successfully", LL_DEBUG);
	}
	hr = ModifyPrivilege(SE_SECURITY_NAME, TRUE);
	if (!SUCCEEDED(hr))
	{
		Log("Failed to modify backup privileges (SE_SECURITY_NAME)", LL_ERROR);
		ret = false;
	}
	else
	{
		Log("Backup privileges set successfully (SE_SECURITY_NAME)", LL_DEBUG);
	}
	hr = ModifyPrivilege(SE_RESTORE_NAME, TRUE);
	if (!SUCCEEDED(hr))
	{
		Log("Failed to modify backup privileges (SE_RESTORE_NAME)", LL_ERROR);
		ret = false;
	}
	else
	{
		Log("Backup privileges set successfully (SE_RESTORE_NAME)", LL_DEBUG);
	}
	return ret;
#else
	return false;
#endif
}
#endif //_WIN32

#ifdef LINUX_DAEMON
bool c_run=true;
void termination_handler(int signum)
{
	c_run=false;
	_exit(2);
}
#endif

#ifdef CONSOLE_ON
int main(int argc, char* argv[])
{
#elif AS_SERVICE
void my_init_fcn(void)
{
#elif EXPORT_METHOD_INT
int start_server_int(unsigned short tcpport, unsigned short udpport, const std::string &pSname, const bool *pDostop, bool use_fqdn)
{
#else
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
#endif

#ifdef _DEBUG
	{
#endif
#ifdef LINUX_DAEMON
		std::cout << "Starting as Daemon..." << std::endl;
		if( fork()==0 )
		{
			setsid();
			for (int i=getdtablesize();i>=0;--i) close(i);
			int i=open("/dev/null",O_RDWR);
			dup(i);
			dup(i);
		}
		else
			exit(0);

		if (signal (SIGINT, termination_handler) == SIG_IGN)
			signal (SIGINT, SIG_IGN);
		if (signal (SIGHUP, termination_handler) == SIG_IGN)
			signal (SIGHUP, SIG_IGN);
		if (signal (SIGTERM, termination_handler) == SIG_IGN)
			signal (SIGTERM, SIG_IGN);

		c_run=true;
#endif

#ifndef _DEBUG
#ifndef AS_SERVICE
#ifndef EXPORT_METHOD_INT
	WriteReg();
#endif
#endif
#endif

	std::string servername;

#ifdef CONSOLE_ON
	if(argc==2)
		servername=argv[1];
#endif

#ifdef _WIN32
	optain_backup_privs();
#endif

#ifdef LOG_FILE
#ifdef _WIN32
	logfile.open("C:\\urinstallsrv.log", std::ios::out | std::ios::binary );
#else
	logfile.open("/var/log/urinstallsrv.log", std::ios::out | std::ios::binary );
#endif
#endif

	/*std::fstream out(testfilename.c_str(), std::ios::out | std::ios::binary );
	if( out.is_open()==false )
		Log("Can't create testfile... Could perhaps cause problems.");

	char* buffer=new char[1024];
	for(size_t i=0;i<1024;++i)
		out.write(buffer, 1024);
	out.close();
	delete[] buffer;
*/

#ifdef _WIN32
	SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
#endif

	TCPServer=new CTCPFileServ;

#ifndef EXPORT_METHOD_INT
	bool suc=TCPServer->Start(55634,55635,servername);
#else
	bool suc=TCPServer->Start(tcpport, udpport, (pSname=="")?servername:pSname, use_fqdn);
#endif

	if(suc==false)
	{
		delete TCPServer;
		TCPServer=NULL;

#ifdef _WIN32
		SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
#endif
		return 99;
	}

#ifndef AS_SERVICE
	while(true)
	{
#if defined(_DEBUG) && defined(_WIN32)
		if( _kbhit() )
		{
			break;
		}
#endif
		bool b=TCPServer->Run();

		if( b==false )
			break;

#ifdef LINUX_DEAMON
		if( c_run==false )
			break;
#endif
#if EXPORT_METHOD_INT
		if(*pDostop==true)
		{
			TCPServer->KickClients();
			break;
		}
#endif
	}

	delete TCPServer;
#endif //AS_SERVICE

#ifdef _WIN32
	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
#endif

#ifndef AS_SERVICE
	return 2;
#endif
#ifdef _DEBUG
	}
#endif
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 Dubalu LLC. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "database_updater.h"

#ifdef XAPIAND_CLUSTERING

#include <utility>                            // for std::move

#include "log.h"                              // for L_OBJ, L_CALL, L_DEBUG, L_WARNING
#include "manager.h"                          // for XapiandManager::manager
#include "server/discovery.h"                 // for Discovery::signal_db_update
#include "string.hh"                          // for string::from_delta
#include "time_point.hh"                      // for time_point_to_ullong

#define NORMALY_UPDATE_AFTER       5s
#define WHEN_BUSY_UPDATE_AFTER    15s
#define FORCE_UPDATE_AFTER        75s

std::mutex DatabaseUpdater::statuses_mtx;
std::unordered_map<DatabaseUpdate, DatabaseUpdater::Status> DatabaseUpdater::statuses;

DatabaseUpdater::DatabaseUpdater(bool forced_, DatabaseUpdate&& update_)
	: forced(forced_),
	  update(std::move(update_)) { }

void
DatabaseUpdater::send(DatabaseUpdate&& update)
{
	L_CALL("DatabaseUpdater::send(<update>)");

	std::shared_ptr<DatabaseUpdater> task;
	unsigned long long next_wakeup_time;

	{
		auto now = std::chrono::system_clock::now();

		std::lock_guard<std::mutex> statuses_lk(DatabaseUpdater::statuses_mtx);
		auto it = DatabaseUpdater::statuses.find(update);

		DatabaseUpdater::Status* status;
		if (it == DatabaseUpdater::statuses.end()) {
			auto& status_ref = DatabaseUpdater::statuses[update] = {
				nullptr,
				time_point_to_ullong(now + FORCE_UPDATE_AFTER)
			};
			status = &status_ref;
			next_wakeup_time = time_point_to_ullong(now + NORMALY_UPDATE_AFTER);
		} else {
			status = &(it->second);
			next_wakeup_time = time_point_to_ullong(now + WHEN_BUSY_UPDATE_AFTER);
		}

		bool forced;
		if (next_wakeup_time > status->max_wakeup_time) {
			next_wakeup_time = status->max_wakeup_time;
			forced = true;
		} else {
			forced = false;
		}

		if (status->task) {
			if (status->task->wakeup_time == next_wakeup_time) {
				return;
			}
			status->task->clear();
		}
		status->task = std::make_shared<DatabaseUpdater>(forced, std::move(update));
		task = status->task;
	}

	scheduler().add(task, next_wakeup_time);
}

void
DatabaseUpdater::run()
{
	L_CALL("DatabaseUpdater::run()");
	L_DEBUG_HOOK("DatabaseUpdater::run", "DatabaseUpdater::run()");

	{
		std::lock_guard<std::mutex> statuses_lk(DatabaseUpdater::statuses_mtx);
		DatabaseUpdater::statuses.erase(update);
	}

	auto start = std::chrono::system_clock::now();

	std::string error;
	try {

		if (auto discovery = XapiandManager::manager->weak_discovery.lock()) {
			L_DEBUG("Replicator was informed database was updated: %s", repr(update.endpoint.to_string()));
			discovery->signal_db_update(update);
		}

	} catch (const Exception& exc) {
		error = exc.get_message();
	}

	auto end = std::chrono::system_clock::now();

	if (error.empty()) {
		L_DEBUG("Updater%s succeeded after %s", forced ? " (forced)" : "", string::from_delta(start, end));
	} else {
		L_WARNING("Updater%s falied after %s: %s", forced ? " (forced)" : "", string::from_delta(start, end), error);
	}
}

#endif
<commit_msg>DatabaseUpdater: Log wording tweaked<commit_after>/*
 * Copyright (C) 2018 Dubalu LLC. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "database_updater.h"

#ifdef XAPIAND_CLUSTERING

#include <utility>                            // for std::move

#include "log.h"                              // for L_OBJ, L_CALL, L_DEBUG, L_WARNING
#include "manager.h"                          // for XapiandManager::manager
#include "server/discovery.h"                 // for Discovery::signal_db_update
#include "string.hh"                          // for string::from_delta
#include "time_point.hh"                      // for time_point_to_ullong

#define NORMALY_UPDATE_AFTER       5s
#define WHEN_BUSY_UPDATE_AFTER    15s
#define FORCE_UPDATE_AFTER        75s

std::mutex DatabaseUpdater::statuses_mtx;
std::unordered_map<DatabaseUpdate, DatabaseUpdater::Status> DatabaseUpdater::statuses;

DatabaseUpdater::DatabaseUpdater(bool forced_, DatabaseUpdate&& update_)
	: forced(forced_),
	  update(std::move(update_)) { }

void
DatabaseUpdater::send(DatabaseUpdate&& update)
{
	L_CALL("DatabaseUpdater::send(<update>)");

	std::shared_ptr<DatabaseUpdater> task;
	unsigned long long next_wakeup_time;

	{
		auto now = std::chrono::system_clock::now();

		std::lock_guard<std::mutex> statuses_lk(DatabaseUpdater::statuses_mtx);
		auto it = DatabaseUpdater::statuses.find(update);

		DatabaseUpdater::Status* status;
		if (it == DatabaseUpdater::statuses.end()) {
			auto& status_ref = DatabaseUpdater::statuses[update] = {
				nullptr,
				time_point_to_ullong(now + FORCE_UPDATE_AFTER)
			};
			status = &status_ref;
			next_wakeup_time = time_point_to_ullong(now + NORMALY_UPDATE_AFTER);
		} else {
			status = &(it->second);
			next_wakeup_time = time_point_to_ullong(now + WHEN_BUSY_UPDATE_AFTER);
		}

		bool forced;
		if (next_wakeup_time > status->max_wakeup_time) {
			next_wakeup_time = status->max_wakeup_time;
			forced = true;
		} else {
			forced = false;
		}

		if (status->task) {
			if (status->task->wakeup_time == next_wakeup_time) {
				return;
			}
			status->task->clear();
		}
		status->task = std::make_shared<DatabaseUpdater>(forced, std::move(update));
		task = status->task;
	}

	scheduler().add(task, next_wakeup_time);
}

void
DatabaseUpdater::run()
{
	L_CALL("DatabaseUpdater::run()");
	L_DEBUG_HOOK("DatabaseUpdater::run", "DatabaseUpdater::run()");

	{
		std::lock_guard<std::mutex> statuses_lk(DatabaseUpdater::statuses_mtx);
		DatabaseUpdater::statuses.erase(update);
	}

	auto start = std::chrono::system_clock::now();

	std::string error;
	try {

		if (auto discovery = XapiandManager::manager->weak_discovery.lock()) {
			discovery->signal_db_update(update);
			L_DEBUG("Replicators where informed about the database update: %s", repr(update.endpoint.to_string()));
		}

	} catch (const Exception& exc) {
		error = exc.get_message();
	}

	auto end = std::chrono::system_clock::now();

	if (error.empty()) {
		L_DEBUG("Updater%s succeeded after %s", forced ? " (forced)" : "", string::from_delta(start, end));
	} else {
		L_WARNING("Updater%s falied after %s: %s", forced ? " (forced)" : "", string::from_delta(start, end), error);
	}
}

#endif
<|endoftext|>


<commit_before>// Time:  O(m * n * max(logm, logn))
// Space: O(m * n)

// BFS with priority queue (min heap), refactored version.
class Solution {
public:
    struct Cell {
        int i;
        int j;
        int height;
    };

    struct Compare {
        bool operator()(const Cell& a, const Cell& b) {
            return a.height > b.height;
        }
    };

    /**
     * @param heights: a matrix of integers
     * @return: an integer
     */
    int trapRainWater(vector<vector<int> > &heights) {
        // Init m_, n_, is_visited_.
        m_ = heights.size();
        n_ = heights[0].size();
        is_visited_ = vector<vector<bool>>(m_, vector<bool>(n_, false));

        int trap = 0;

        // Put the cells on the border into min heap.
        for (int i = 0; i < m_; ++i) {
            heap_.emplace(Cell{i, 0, heights[i][0]});
            heap_.emplace(Cell{i, n_ - 1, heights[i][n_ - 1]});
        }
        for (int j = 0; j < n_; ++j) {
            heap_.emplace(Cell{0, j, heights[0][j]});
            heap_.emplace(Cell{m_ - 1, j, heights[m_ - 1][j]});
        }

        // BFS with priority queue (min heap)
        while (!heap_.empty()) {
            Cell c = heap_.top();
            heap_.pop();
            is_visited_[c.i][c.j] = true;

            trap += fill(heights, c.i + 1, c.j, c.height); // Up
            trap += fill(heights, c.i - 1, c.j, c.height); // Down
            trap += fill(heights, c.i, c.j + 1, c.height); // Right
            trap += fill(heights, c.i, c.j - 1, c.height); // Left
        }

        return trap;
    }

    int fill(vector<vector<int>>& heights, int i, int j, int height) {
        // Out of border.
        if ( i < 0 || i >= m_ || j < 0 || j >= n_) {
            return 0;
        }

        // Fill unvisited cell.
        if (!is_visited_[i][j]) {
            is_visited_[i][j] = true; // Marked as visited.
            heap_.emplace(Cell{i, j, max(height, heights[i][j])});
            return max(0, height - heights[i][j]); // Fill in the gap.
        }

        return 0;
    }

private:
    int m_;
    int n_;
    vector<vector<bool>> is_visited_;
    priority_queue<Cell ,vector<Cell>, Compare> heap_; // Use min heap to get the lowerest cell.
};

// Time:  O(m * n * max(logm, logn))
// Space: O(m * n)
// BFS with priority queue (min heap)
class Solution2 {
public:
    struct Cell {
        int i;
        int j;
        int height;
    };

    /**
     * @param heights: a matrix of integers
     * @return: an integer
     */
    int trapRainWater(vector<vector<int> > &heights) {
        const int m = heights.size();
        const int n = heights[0].size();
        int trap = 0;
        vector<vector<bool>> is_visited(m, vector<bool>(n, false));

        // Use min heap to get the lowerest Cell.
        auto comp = [](const Cell& a, const Cell& b ) { return a.height > b.height; };
        priority_queue<Cell , vector<Cell>, decltype(comp)> heap(comp);

        // Put the Cells on the border into min heap.
        for (int i = 0; i < m; ++i) {
            heap.emplace(Cell{i, 0, heights[i][0]});
            heap.emplace(Cell{i, n - 1, heights[i][n - 1]});
        }
        for (int j = 0; j < n; ++j) {
            heap.emplace(Cell{0, j, heights[0][j]});
            heap.emplace(Cell{m - 1, j, heights[m - 1][j]});
        }

        // BFS with priority queue (min heap)
        while (!heap.empty()) {
            // Get the lowest Cell.
            Cell c = heap.top();
            heap.pop();
            is_visited[c.i][c.j] = true;

            // Up
            if (c.i + 1 < m && !is_visited[c.i + 1][c.j]) {
                is_visited[c.i + 1][c.j] = true;
                trap += max(0, c.height - heights[c.i + 1][c.j]); // Fill in the gap.
                heap.emplace(Cell{c.i + 1, c.j, max(c.height,
                                                    heights[c.i + 1][c.j])});
            }
            // Down
            if (c.i - 1 >= 0 && !is_visited[c.i - 1][c.j]) {
                is_visited[c.i - 1][c.j] = true;
                trap += max(0, c.height - heights[c.i - 1][c.j]); // Fill in the gap.
                heap.emplace(Cell{c.i - 1, c.j, max(c.height,
                                                    heights[c.i - 1][c.j])});
            }
            // Right
            if (c.j + 1 < n && !is_visited[c.i][c.j + 1]) {
                is_visited[c.i][c.j + 1] = true;
                trap += max(0, c.height - heights[c.i][c.j + 1]); // Fill in the gap.
                heap.emplace(Cell{c.i, c.j + 1, max(c.height,
                                                    heights[c.i][c.j + 1])});
            }
            // Left
            if (c.j - 1 >= 0 && !is_visited[c.i][c.j - 1]) {
                is_visited[c.i][c.j - 1] = true;
                trap += max(0, c.height - heights[c.i][c.j - 1]); // Fill in the gap.
                heap.emplace(Cell{c.i, c.j - 1, max(c.height,
                                                    heights[c.i][c.j - 1])});
            }
        }

        return trap;
    }
};
<commit_msg>Update trapping-rain-water-ii.cpp<commit_after>// Time:  O(m * n * (logm + logn))
// Space: O(m * n)

// BFS with priority queue (min heap), refactored version.
class Solution {
public:
    struct Cell {
        int i;
        int j;
        int height;
    };

    struct Compare {
        bool operator()(const Cell& a, const Cell& b) {
            return a.height > b.height;
        }
    };

    /**
     * @param heights: a matrix of integers
     * @return: an integer
     */
    int trapRainWater(vector<vector<int> > &heights) {
        // Init m_, n_, is_visited_.
        m_ = heights.size();
        n_ = heights[0].size();
        is_visited_ = vector<vector<bool>>(m_, vector<bool>(n_, false));

        int trap = 0;

        // Put the cells on the border into min heap.
        for (int i = 0; i < m_; ++i) {
            heap_.emplace(Cell{i, 0, heights[i][0]});
            heap_.emplace(Cell{i, n_ - 1, heights[i][n_ - 1]});
        }
        for (int j = 0; j < n_; ++j) {
            heap_.emplace(Cell{0, j, heights[0][j]});
            heap_.emplace(Cell{m_ - 1, j, heights[m_ - 1][j]});
        }

        // BFS with priority queue (min heap)
        while (!heap_.empty()) {
            Cell c = heap_.top();
            heap_.pop();
            is_visited_[c.i][c.j] = true;

            trap += fill(heights, c.i + 1, c.j, c.height); // Up
            trap += fill(heights, c.i - 1, c.j, c.height); // Down
            trap += fill(heights, c.i, c.j + 1, c.height); // Right
            trap += fill(heights, c.i, c.j - 1, c.height); // Left
        }

        return trap;
    }

    int fill(vector<vector<int>>& heights, int i, int j, int height) {
        // Out of border.
        if ( i < 0 || i >= m_ || j < 0 || j >= n_) {
            return 0;
        }

        // Fill unvisited cell.
        if (!is_visited_[i][j]) {
            is_visited_[i][j] = true; // Marked as visited.
            heap_.emplace(Cell{i, j, max(height, heights[i][j])});
            return max(0, height - heights[i][j]); // Fill in the gap.
        }

        return 0;
    }

private:
    int m_;
    int n_;
    vector<vector<bool>> is_visited_;
    priority_queue<Cell ,vector<Cell>, Compare> heap_; // Use min heap to get the lowerest cell.
};

// Time:  O(m * n * (logm + logn))
// Space: O(m * n)
// BFS with priority queue (min heap)
class Solution2 {
public:
    struct Cell {
        int i;
        int j;
        int height;
    };

    /**
     * @param heights: a matrix of integers
     * @return: an integer
     */
    int trapRainWater(vector<vector<int> > &heights) {
        const int m = heights.size();
        const int n = heights[0].size();
        int trap = 0;
        vector<vector<bool>> is_visited(m, vector<bool>(n, false));

        // Use min heap to get the lowerest Cell.
        auto comp = [](const Cell& a, const Cell& b ) { return a.height > b.height; };
        priority_queue<Cell , vector<Cell>, decltype(comp)> heap(comp);

        // Put the Cells on the border into min heap.
        for (int i = 0; i < m; ++i) {
            heap.emplace(Cell{i, 0, heights[i][0]});
            heap.emplace(Cell{i, n - 1, heights[i][n - 1]});
        }
        for (int j = 0; j < n; ++j) {
            heap.emplace(Cell{0, j, heights[0][j]});
            heap.emplace(Cell{m - 1, j, heights[m - 1][j]});
        }

        // BFS with priority queue (min heap)
        while (!heap.empty()) {
            // Get the lowest Cell.
            Cell c = heap.top();
            heap.pop();
            is_visited[c.i][c.j] = true;

            // Up
            if (c.i + 1 < m && !is_visited[c.i + 1][c.j]) {
                is_visited[c.i + 1][c.j] = true;
                trap += max(0, c.height - heights[c.i + 1][c.j]); // Fill in the gap.
                heap.emplace(Cell{c.i + 1, c.j, max(c.height,
                                                    heights[c.i + 1][c.j])});
            }
            // Down
            if (c.i - 1 >= 0 && !is_visited[c.i - 1][c.j]) {
                is_visited[c.i - 1][c.j] = true;
                trap += max(0, c.height - heights[c.i - 1][c.j]); // Fill in the gap.
                heap.emplace(Cell{c.i - 1, c.j, max(c.height,
                                                    heights[c.i - 1][c.j])});
            }
            // Right
            if (c.j + 1 < n && !is_visited[c.i][c.j + 1]) {
                is_visited[c.i][c.j + 1] = true;
                trap += max(0, c.height - heights[c.i][c.j + 1]); // Fill in the gap.
                heap.emplace(Cell{c.i, c.j + 1, max(c.height,
                                                    heights[c.i][c.j + 1])});
            }
            // Left
            if (c.j - 1 >= 0 && !is_visited[c.i][c.j - 1]) {
                is_visited[c.i][c.j - 1] = true;
                trap += max(0, c.height - heights[c.i][c.j - 1]); // Fill in the gap.
                heap.emplace(Cell{c.i, c.j - 1, max(c.height,
                                                    heights[c.i][c.j - 1])});
            }
        }

        return trap;
    }
};
<|endoftext|>